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.

435 lines
11 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. PpHotSwap.c
  5. Abstract:
  6. This file implements support for hotswap devices.
  7. Author:
  8. Adrian J. Oney (AdriaO) Feb 2001
  9. Revision History:
  10. --*/
  11. #include "pnpmgrp.h"
  12. #include "pihotswap.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGE, PpHotSwapInitRemovalPolicy)
  15. #pragma alloc_text(PAGE, PpHotSwapUpdateRemovalPolicy)
  16. #pragma alloc_text(PAGE, PpHotSwapGetDevnodeRemovalPolicy)
  17. #pragma alloc_text(PAGE, PiHotSwapGetDefaultBusRemovalPolicy)
  18. #pragma alloc_text(PAGE, PiHotSwapGetDetachableNode)
  19. #endif
  20. VOID
  21. PpHotSwapInitRemovalPolicy(
  22. OUT PDEVICE_NODE DeviceNode
  23. )
  24. /*++
  25. Routine Description:
  26. This function initializes the removal policy information for a device node.
  27. Arguments:
  28. DeviceNode - DevNode to update policy.
  29. Return Value:
  30. Nothing.
  31. --*/
  32. {
  33. PAGED_CODE();
  34. DeviceNode->RemovalPolicy = (UCHAR) RemovalPolicyNotDetermined;
  35. DeviceNode->HardwareRemovalPolicy = (UCHAR) RemovalPolicyNotDetermined;
  36. }
  37. VOID
  38. PpHotSwapUpdateRemovalPolicy(
  39. IN PDEVICE_NODE DeviceNode
  40. )
  41. /*++
  42. Routine Description:
  43. This function updates the removal policy by retrieving the appropriate
  44. data from the registry or drivers.
  45. Arguments:
  46. DeviceNode - DevNode to update policy on.
  47. Return Value:
  48. Nothing.
  49. --*/
  50. {
  51. NTSTATUS status;
  52. DEVICE_REMOVAL_POLICY deviceRemovalPolicy, parentPolicy;
  53. PDEVICE_NODE detachableNode;
  54. ULONG policyLength, policyCharacteristics;
  55. PAGED_CODE();
  56. PPDEVNODE_ASSERT_LOCK_HELD(PPL_TREEOP_ALLOW_READS);
  57. //
  58. // First find the detachable node - it holds our policy data, and is
  59. // special as it may make suggestions.
  60. //
  61. PiHotSwapGetDetachableNode(DeviceNode, &detachableNode);
  62. //
  63. // We aren't in fact removable. Finish now.
  64. //
  65. if (detachableNode == NULL) {
  66. DeviceNode->RemovalPolicy = (UCHAR) RemovalPolicyExpectNoRemoval;
  67. DeviceNode->HardwareRemovalPolicy = (UCHAR) RemovalPolicyExpectNoRemoval;
  68. return;
  69. }
  70. //
  71. // Check the stack for an explicit policy...
  72. //
  73. policyCharacteristics =
  74. ((DeviceNode->PhysicalDeviceObject->Characteristics) &
  75. FILE_CHARACTERISTICS_REMOVAL_POLICY_MASK);
  76. if (policyCharacteristics == FILE_CHARACTERISTICS_EXPECT_ORDERLY_REMOVAL) {
  77. deviceRemovalPolicy = RemovalPolicyExpectOrderlyRemoval;
  78. } else if (policyCharacteristics == FILE_CHARACTERISTICS_EXPECT_SURPRISE_REMOVAL) {
  79. deviceRemovalPolicy = RemovalPolicyExpectSurpriseRemoval;
  80. } else if (DeviceNode != detachableNode) {
  81. //
  82. // We didn't get any good guesses. Therefore use the weakest policy.
  83. //
  84. deviceRemovalPolicy = RemovalPolicyUnspecified;
  85. } else {
  86. //
  87. // If we're the detach point, then we win.
  88. //
  89. PiHotSwapGetDefaultBusRemovalPolicy(DeviceNode, &deviceRemovalPolicy);
  90. }
  91. if (DeviceNode != detachableNode) {
  92. //
  93. // Do we have a winning policy? There are two possible algorithms for
  94. // coming to such a decision.
  95. // 1) Best policy is stored back at the detach point. If a child has a
  96. // better policy, the detach point is updated.
  97. // 2) Policy is inherited downwards from the parent.
  98. //
  99. // We choose the second algorithm because devnode start orders may
  100. // change scenario to scenario, and we favor determinism (same results
  101. // each time) over opportunism (nonmarked child gets write caching
  102. // enabled only on Tuesdays.)
  103. //
  104. parentPolicy = DeviceNode->Parent->RemovalPolicy;
  105. if (deviceRemovalPolicy > parentPolicy) {
  106. //
  107. // Seems dad was right afterall...
  108. //
  109. deviceRemovalPolicy = parentPolicy;
  110. }
  111. }
  112. //
  113. // Update the policy hardware policy and the overall policy in case there's
  114. // no registry override.
  115. //
  116. DeviceNode->RemovalPolicy = (UCHAR) deviceRemovalPolicy;
  117. DeviceNode->HardwareRemovalPolicy = (UCHAR) deviceRemovalPolicy;
  118. //
  119. // We might not have to ask the stack anything. Check for a registry
  120. // override.
  121. //
  122. policyLength = sizeof(DEVICE_REMOVAL_POLICY);
  123. status = PiGetDeviceRegistryProperty(
  124. DeviceNode->PhysicalDeviceObject,
  125. REG_DWORD,
  126. REGSTR_VALUE_REMOVAL_POLICY,
  127. NULL,
  128. &deviceRemovalPolicy,
  129. &policyLength
  130. );
  131. //
  132. // If we have an override, set that as the policy.
  133. //
  134. if (NT_SUCCESS(status) &&
  135. ((deviceRemovalPolicy == RemovalPolicyExpectOrderlyRemoval) ||
  136. (deviceRemovalPolicy == RemovalPolicyExpectSurpriseRemoval))) {
  137. DeviceNode->RemovalPolicy = (UCHAR) deviceRemovalPolicy;
  138. }
  139. }
  140. VOID
  141. PpHotSwapGetDevnodeRemovalPolicy(
  142. IN PDEVICE_NODE DeviceNode,
  143. IN BOOLEAN IncludeRegistryOverride,
  144. OUT PDEVICE_REMOVAL_POLICY RemovalPolicy
  145. )
  146. /*++
  147. Routine Description:
  148. This function retrieves the removal policy for a device node.
  149. Arguments:
  150. DeviceNode - DevNode to retrieve policy from.
  151. IncludeRegistryOverride - TRUE if a registry override should be taken into
  152. account if present. FALSE if the check should be
  153. restricted to the hardware.
  154. RemovalPolicy - Receives removal policy.
  155. Return Value:
  156. Nothing.
  157. --*/
  158. {
  159. PDEVICE_NODE detachableNode;
  160. DEVICE_REMOVAL_POLICY reportedPolicy;
  161. PAGED_CODE();
  162. //
  163. // Ensure the tree won't be edited while we examine it.
  164. //
  165. PpDevNodeLockTree(PPL_SIMPLE_READ);
  166. if (IncludeRegistryOverride) {
  167. reportedPolicy = DeviceNode->RemovalPolicy;
  168. } else {
  169. reportedPolicy = DeviceNode->HardwareRemovalPolicy;
  170. }
  171. if (reportedPolicy == RemovalPolicyNotDetermined) {
  172. //
  173. // We haven't started yet or asked the bus. Our policy is based on
  174. // whether the device is removable or ejectable.
  175. //
  176. PiHotSwapGetDetachableNode(DeviceNode, &detachableNode);
  177. if (detachableNode == NULL) {
  178. reportedPolicy = RemovalPolicyExpectNoRemoval;
  179. } else if (IopDeviceNodeFlagsToCapabilities(detachableNode)->EjectSupported) {
  180. //
  181. // Ejectable devices require orderly removal. We will assume the
  182. // user knows this.
  183. //
  184. reportedPolicy = RemovalPolicyExpectOrderlyRemoval;
  185. } else {
  186. ASSERT(IopDeviceNodeFlagsToCapabilities(detachableNode)->Removable);
  187. //
  188. // Removal nonstarted devices can be pulled at any instant.
  189. //
  190. reportedPolicy = RemovalPolicyExpectSurpriseRemoval;
  191. }
  192. } else {
  193. //
  194. // The devnode has a cached policy. Cut down on the options.
  195. //
  196. switch(reportedPolicy) {
  197. case RemovalPolicyExpectNoRemoval:
  198. case RemovalPolicyExpectOrderlyRemoval:
  199. case RemovalPolicyExpectSurpriseRemoval:
  200. //
  201. // Leave unchanged.
  202. //
  203. break;
  204. case RemovalPolicySuggestSurpriseRemoval:
  205. reportedPolicy = RemovalPolicyExpectSurpriseRemoval;
  206. break;
  207. default:
  208. ASSERT(0);
  209. //
  210. // Fall through.
  211. //
  212. case RemovalPolicyUnspecified:
  213. //
  214. // Unspecified is treated as orderly since the diversity of
  215. // busses favor high-speed orderly connections over consumer
  216. // connections.
  217. //
  218. // Fall through
  219. //
  220. case RemovalPolicySuggestOrderlyRemoval:
  221. reportedPolicy = RemovalPolicyExpectOrderlyRemoval;
  222. break;
  223. }
  224. }
  225. PpDevNodeUnlockTree(PPL_SIMPLE_READ);
  226. *RemovalPolicy = reportedPolicy;
  227. }
  228. VOID
  229. PiHotSwapGetDefaultBusRemovalPolicy(
  230. IN PDEVICE_NODE DeviceNode,
  231. OUT PDEVICE_REMOVAL_POLICY RemovalPolicy
  232. )
  233. /*++
  234. Routine Description:
  235. This function gets the default removal policy for a bus. This should be
  236. turned into a query in future designs.
  237. Arguments:
  238. DeviceNode - DevNode to examine. This devnode should be the detach point.
  239. RemovalPolicy - Receives removal policy for the node.
  240. Return Value:
  241. None.
  242. --*/
  243. {
  244. DEVICE_REMOVAL_POLICY deviceRemovalPolicy;
  245. PAGED_CODE();
  246. PPDEVNODE_ASSERT_LOCK_HELD(PPL_TREEOP_ALLOW_READS);
  247. if ((DeviceNode->InstancePath.Length > 8) &&
  248. (!_wcsnicmp(DeviceNode->InstancePath.Buffer, L"USB\\", 4))) {
  249. deviceRemovalPolicy = RemovalPolicySuggestSurpriseRemoval;
  250. } else if ((DeviceNode->InstancePath.Length > 10) &&
  251. (!_wcsnicmp(DeviceNode->InstancePath.Buffer, L"1394\\", 5))) {
  252. deviceRemovalPolicy = RemovalPolicySuggestSurpriseRemoval;
  253. } else if ((DeviceNode->InstancePath.Length > 10) &&
  254. (!_wcsnicmp(DeviceNode->InstancePath.Buffer, L"SBP2\\", 5))) {
  255. deviceRemovalPolicy = RemovalPolicySuggestSurpriseRemoval;
  256. } else if ((DeviceNode->InstancePath.Length > 14) &&
  257. (!_wcsnicmp(DeviceNode->InstancePath.Buffer, L"PCMCIA\\", 7))) {
  258. deviceRemovalPolicy = RemovalPolicySuggestSurpriseRemoval;
  259. } else if ((DeviceNode->InstancePath.Length > 8) &&
  260. (!_wcsnicmp(DeviceNode->InstancePath.Buffer, L"PCI\\", 4)) &&
  261. (DeviceNode->Parent->ServiceName.Length == 12) &&
  262. (!_wcsicmp(DeviceNode->Parent->ServiceName.Buffer, L"PCMCIA"))) {
  263. deviceRemovalPolicy = RemovalPolicySuggestSurpriseRemoval;
  264. } else {
  265. deviceRemovalPolicy = RemovalPolicySuggestOrderlyRemoval;
  266. }
  267. *RemovalPolicy = deviceRemovalPolicy;
  268. }
  269. VOID
  270. PiHotSwapGetDetachableNode(
  271. IN PDEVICE_NODE DeviceNode,
  272. OUT PDEVICE_NODE *DetachableNode
  273. )
  274. /*++
  275. Routine Description:
  276. This function starts at the DeviceNode and walks up the tree to find the
  277. first node that is removable.
  278. Arguments:
  279. DeviceNode - DevNode to start walk from.
  280. DetachableNode - Receives detachable node, NULL if none.
  281. Return Value:
  282. Nothing.
  283. --*/
  284. {
  285. PDEVICE_NODE currentNode;
  286. PAGED_CODE();
  287. PPDEVNODE_ASSERT_LOCK_HELD(PPL_SIMPLE_READ);
  288. //
  289. // We haven't started yet or asked the bus. Our policy is based on
  290. // whether the device is removable or ejectable.
  291. //
  292. for(currentNode = DeviceNode;
  293. currentNode != NULL;
  294. currentNode = currentNode->Parent) {
  295. if ((IopDeviceNodeFlagsToCapabilities(currentNode)->Removable) ||
  296. (IopDeviceNodeFlagsToCapabilities(currentNode)->EjectSupported)) {
  297. break;
  298. }
  299. }
  300. *DetachableNode = currentNode;
  301. }