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.

508 lines
15 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. pnpstart.c
  5. Abstract:
  6. This module implements new Plug-And-Play driver entries and IRPs.
  7. Author:
  8. Shie-Lin Tzong (shielint) June-16-1995
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. */
  13. #include "pnpmgrp.h"
  14. #pragma hdrstop
  15. #ifdef POOL_TAGGING
  16. #undef ExAllocatePool
  17. #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'ddpP')
  18. #endif
  19. typedef struct _DEVICE_LIST_CONTEXT {
  20. ULONG DeviceCount;
  21. BOOLEAN Reallocation;
  22. PDEVICE_OBJECT DeviceList[1];
  23. } DEVICE_LIST_CONTEXT, *PDEVICE_LIST_CONTEXT;
  24. NTSTATUS
  25. IopAssignResourcesToDevices (
  26. IN ULONG DeviceCount,
  27. IN PIOP_RESOURCE_REQUEST RequestTable,
  28. IN BOOLEAN DoBootConfigs,
  29. OUT PBOOLEAN RebalancePerformed
  30. );
  31. NTSTATUS
  32. IopGetDriverDeviceList(
  33. IN PDRIVER_OBJECT DriverObject,
  34. OUT PDEVICE_LIST_CONTEXT *DeviceList
  35. );
  36. NTSTATUS
  37. IopProcessAssignResourcesWorker(
  38. IN PDEVICE_NODE DeviceNode,
  39. IN PVOID Context
  40. );
  41. #ifdef ALLOC_PRAGMA
  42. #pragma alloc_text(PAGE, IopAssignResourcesToDevices)
  43. #pragma alloc_text(PAGE, IopProcessAssignResources)
  44. #pragma alloc_text(PAGE, IopProcessAssignResourcesWorker)
  45. #pragma alloc_text(PAGE, IopWriteAllocatedResourcesToRegistry)
  46. #endif // ALLOC_PRAGMA
  47. //
  48. // The following routines should be removed once the real
  49. // Resource Assign code is done.
  50. //
  51. NTSTATUS
  52. IopAssignResourcesToDevices(
  53. IN ULONG DeviceCount,
  54. IN OUT PIOP_RESOURCE_REQUEST RequestTable,
  55. IN BOOLEAN DoBootConfigs,
  56. OUT PBOOLEAN RebalancePerformed
  57. )
  58. /*++
  59. Routine Description:
  60. This routine takes an input array of IOP_RESOURCE_REQUEST structures, and
  61. allocates resource for the physical device object specified in
  62. the structure. The allocated resources are automatically recorded
  63. in the registry.
  64. Arguments:
  65. DeviceCount - Supplies the number of device objects whom we need to
  66. allocate resource to. That is the number of entries
  67. in the RequestTable.
  68. RequestTable - Supplies an array of IOP_RESOURCE_REQUEST structures which
  69. contains the Physical device object to allocate resource to.
  70. Upon entry, the ResourceAssignment pointer is NULL and on
  71. return the allocated resource is returned via the this pointer.
  72. DoBootConfigs - Allow assignment of BOOT configs.
  73. Return Value:
  74. The status returned is the final completion status of the operation.
  75. NOTE:
  76. If NTSTATUS_SUCCESS is returned, the resource allocation for *all* the devices
  77. specified is succeeded. Otherwise, one or more are failed and caller must
  78. examine the ResourceAssignment pointer in each IOP_RESOURCE_REQUEST structure to
  79. determine which devices failed and which succeeded.
  80. --*/
  81. {
  82. NTSTATUS status;
  83. ULONG i;
  84. PAGED_CODE();
  85. ASSERT(DeviceCount != 0);
  86. for (i = 0; i < DeviceCount; i++) {
  87. //
  88. // Initialize table entry.
  89. //
  90. if (PpCallerInitializesRequestTable == TRUE) {
  91. RequestTable[i].Position = i;
  92. }
  93. RequestTable[i].ResourceAssignment = NULL;
  94. RequestTable[i].Status = 0;
  95. RequestTable[i].Flags = 0;
  96. RequestTable[i].AllocationType = ArbiterRequestPnpEnumerated;
  97. if (((PDEVICE_NODE)(RequestTable[i].PhysicalDevice->DeviceObjectExtension->DeviceNode))->Flags & DNF_MADEUP) {
  98. ULONG reportedDevice = 0;
  99. HANDLE hInstance;
  100. status = IopDeviceObjectToDeviceInstance(RequestTable[i].PhysicalDevice, &hInstance, KEY_READ);
  101. if (NT_SUCCESS(status)) {
  102. ULONG resultSize = 0;
  103. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
  104. UNICODE_STRING unicodeString;
  105. PiWstrToUnicodeString(&unicodeString, REGSTR_VALUE_DEVICE_REPORTED);
  106. status = ZwQueryValueKey( hInstance,
  107. &unicodeString,
  108. KeyValuePartialInformation,
  109. (PVOID)buffer,
  110. sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG),
  111. &resultSize);
  112. if (NT_SUCCESS(status)) {
  113. reportedDevice = *(PULONG)(((PKEY_VALUE_PARTIAL_INFORMATION)buffer)->Data);
  114. }
  115. ZwClose(hInstance);
  116. }
  117. //
  118. // Change the AllocationType for reported devices.
  119. //
  120. if (reportedDevice) {
  121. RequestTable[i].AllocationType = ArbiterRequestLegacyReported;
  122. }
  123. }
  124. RequestTable[i].ResourceRequirements = NULL;
  125. }
  126. //
  127. // Allocate memory to build a IOP_ASSIGN table to call IopAllocateResources()
  128. //
  129. status = IopAllocateResources( &DeviceCount,
  130. &RequestTable,
  131. FALSE,
  132. DoBootConfigs,
  133. RebalancePerformed);
  134. return status;
  135. }
  136. BOOLEAN
  137. IopProcessAssignResources(
  138. IN PDEVICE_NODE DeviceNode,
  139. IN BOOLEAN Reallocation,
  140. OUT BOOLEAN *RebalancePerformed
  141. )
  142. /*++
  143. Routine Description:
  144. This function attempts to assign resources to device under the subtree on
  145. which AddDevice has been performed. Prior to the completion of all Boot Bus
  146. Extenders in the system, this routine attempts allocation first so that devices
  147. with no requirements and no boot config get processed. If there are no such devices,
  148. then it attempts to allocate resources for devices with boot config. If there are no
  149. devices with boot config, then other devices (requirements but no boot config)
  150. get processed. During later part of boot, it attempts allocation only once
  151. (since we should have already reserved all the boot configs).
  152. Parameters:
  153. DeviceNode - specifies the root of the subtree under which resources will be
  154. allocated.
  155. Reallocation - if TRUE, we will attempt allocation for devices with resource conflict
  156. problem in addition to other devices.
  157. RebalancePerformed - recieves whether a rebalance was successfully comp[eted.
  158. Return Value:
  159. TRUE if resources got assigned to any device, otherwise FALSE.
  160. --*/
  161. {
  162. PDEVICE_NODE deviceNode;
  163. PDEVICE_LIST_CONTEXT context;
  164. BOOLEAN resourcesAssigned, tryAgain;
  165. ULONG count, i, attempt, maxAttempts;
  166. PIOP_RESOURCE_REQUEST requestTable;
  167. PAGED_CODE();
  168. resourcesAssigned = FALSE;
  169. tryAgain = TRUE;
  170. maxAttempts = (IopBootConfigsReserved)? 1 : 2;
  171. for (attempt = 0; !resourcesAssigned && tryAgain && attempt < maxAttempts; attempt++) {
  172. tryAgain = FALSE;
  173. //
  174. // Allocate and init memory for resource context
  175. //
  176. context = (PDEVICE_LIST_CONTEXT) ExAllocatePool(
  177. PagedPool,
  178. sizeof(DEVICE_LIST_CONTEXT) +
  179. sizeof(PDEVICE_OBJECT) * IopNumberDeviceNodes
  180. );
  181. if (!context) {
  182. return FALSE;
  183. }
  184. context->DeviceCount = 0;
  185. context->Reallocation = Reallocation;
  186. //
  187. // Parse the device node subtree to determine which devices need resources
  188. //
  189. IopProcessAssignResourcesWorker(DeviceNode, context);
  190. count = context->DeviceCount;
  191. if (count == 0) {
  192. ExFreePool(context);
  193. return FALSE;
  194. }
  195. //
  196. // Need to assign resources to devices. Build the resource request table and call
  197. // resource assignment routine.
  198. //
  199. requestTable = (PIOP_RESOURCE_REQUEST) ExAllocatePool(
  200. PagedPool,
  201. sizeof(IOP_RESOURCE_REQUEST) * count
  202. );
  203. if (requestTable) {
  204. for (i = 0; i < count; i++) {
  205. requestTable[i].Priority = 0;
  206. requestTable[i].PhysicalDevice = context->DeviceList[i];
  207. }
  208. //
  209. // Assign resources
  210. //
  211. IopAssignResourcesToDevices(
  212. count,
  213. requestTable,
  214. (attempt == 0) ? IopBootConfigsReserved : TRUE,
  215. RebalancePerformed
  216. );
  217. //
  218. // Check the results
  219. //
  220. for (i = 0; i < count; i++) {
  221. deviceNode = (PDEVICE_NODE)
  222. requestTable[i].PhysicalDevice->DeviceObjectExtension->DeviceNode;
  223. if (NT_SUCCESS(requestTable[i].Status)) {
  224. if (requestTable[i].ResourceAssignment) {
  225. deviceNode->ResourceList = requestTable[i].ResourceAssignment;
  226. deviceNode->ResourceListTranslated = requestTable[i].TranslatedResourceAssignment;
  227. } else {
  228. deviceNode->Flags |= DNF_NO_RESOURCE_REQUIRED;
  229. }
  230. PipSetDevNodeState(deviceNode, DeviceNodeResourcesAssigned, NULL);
  231. deviceNode->UserFlags &= ~DNUF_NEED_RESTART;
  232. resourcesAssigned = TRUE;
  233. } else {
  234. switch (requestTable[i].Status) {
  235. case STATUS_RETRY:
  236. tryAgain = TRUE;
  237. break;
  238. case STATUS_DEVICE_CONFIGURATION_ERROR:
  239. PipSetDevNodeProblem(deviceNode, CM_PROB_NO_SOFTCONFIG);
  240. break;
  241. case STATUS_PNP_BAD_MPS_TABLE:
  242. PipSetDevNodeProblem(deviceNode, CM_PROB_BIOS_TABLE);
  243. break;
  244. case STATUS_PNP_TRANSLATION_FAILED:
  245. PipSetDevNodeProblem(deviceNode, CM_PROB_TRANSLATION_FAILED);
  246. break;
  247. case STATUS_PNP_IRQ_TRANSLATION_FAILED:
  248. PipSetDevNodeProblem(deviceNode, CM_PROB_IRQ_TRANSLATION_FAILED);
  249. break;
  250. case STATUS_RESOURCE_TYPE_NOT_FOUND:
  251. PipSetDevNodeProblem(deviceNode, CM_PROB_UNKNOWN_RESOURCE);
  252. break;
  253. default:
  254. PipSetDevNodeProblem(deviceNode, CM_PROB_NORMAL_CONFLICT);
  255. break;
  256. }
  257. }
  258. }
  259. ExFreePool(requestTable);
  260. }
  261. ExFreePool(context);
  262. }
  263. return resourcesAssigned;
  264. }
  265. NTSTATUS
  266. IopProcessAssignResourcesWorker(
  267. IN PDEVICE_NODE DeviceNode,
  268. IN PVOID Context
  269. )
  270. /*++
  271. Routine Description:
  272. This functions searches the DeviceNode subtree to locate all the device objects
  273. which have been successfully added to their drivers and waiting for resources to
  274. be started.
  275. Parameters:
  276. DeviceNode - specifies the device node whose subtree is to be checked for AssignRes.
  277. Context - specifies a pointer to a structure to pass resource assignment information.
  278. Return Value:
  279. TRUE.
  280. --*/
  281. {
  282. PDEVICE_LIST_CONTEXT resourceContext = (PDEVICE_LIST_CONTEXT) Context;
  283. PAGED_CODE();
  284. //
  285. // If the device node/object has not been add, skip it.
  286. //
  287. if (resourceContext->Reallocation &&
  288. (PipIsDevNodeProblem(DeviceNode, CM_PROB_NORMAL_CONFLICT) ||
  289. PipIsDevNodeProblem(DeviceNode, CM_PROB_TRANSLATION_FAILED) ||
  290. PipIsDevNodeProblem(DeviceNode, CM_PROB_IRQ_TRANSLATION_FAILED))) {
  291. PipClearDevNodeProblem(DeviceNode);
  292. }
  293. if (!PipDoesDevNodeHaveProblem(DeviceNode)) {
  294. //
  295. // If the device object has not been started and has no resources yet.
  296. // Append it to our list.
  297. //
  298. if (DeviceNode->State == DeviceNodeDriversAdded) {
  299. resourceContext->DeviceList[resourceContext->DeviceCount] =
  300. DeviceNode->PhysicalDeviceObject;
  301. resourceContext->DeviceCount++;
  302. } else {
  303. //
  304. // Acquire enumeration mutex to make sure its children won't change by
  305. // someone else. Note, the current device node is protected by its parent's
  306. // Enumeration mutex and it won't disappear either.
  307. //
  308. //
  309. // Recursively mark all of our children deleted.
  310. //
  311. PipForAllChildDeviceNodes(DeviceNode, IopProcessAssignResourcesWorker, Context);
  312. }
  313. }
  314. return STATUS_SUCCESS;
  315. }
  316. NTSTATUS
  317. IopWriteAllocatedResourcesToRegistry (
  318. PDEVICE_NODE DeviceNode,
  319. PCM_RESOURCE_LIST CmResourceList,
  320. ULONG Length
  321. )
  322. /*++
  323. Routine Description:
  324. This routine writes allocated resources for a device to its control key of device
  325. instance path key.
  326. Arguments:
  327. DeviceNode - Supplies a pointer to the device node structure of the device.
  328. CmResourceList - Supplies a pointer to the device's allocated CM resource list.
  329. Length - Supplies the length of the CmResourceList.
  330. Return Value:
  331. The status returned is the final completion status of the operation.
  332. --*/
  333. {
  334. NTSTATUS status;
  335. PDEVICE_OBJECT deviceObject = DeviceNode->PhysicalDeviceObject;
  336. HANDLE handle, handlex;
  337. UNICODE_STRING unicodeName;
  338. PiLockPnpRegistry(FALSE);
  339. status = IopDeviceObjectToDeviceInstance(
  340. deviceObject,
  341. &handlex,
  342. KEY_ALL_ACCESS);
  343. if (NT_SUCCESS(status)) {
  344. //
  345. // Open the LogConfig key of the device instance.
  346. //
  347. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_CONTROL);
  348. status = IopCreateRegistryKeyEx( &handle,
  349. handlex,
  350. &unicodeName,
  351. KEY_ALL_ACCESS,
  352. REG_OPTION_VOLATILE,
  353. NULL
  354. );
  355. ZwClose(handlex);
  356. if (NT_SUCCESS(status)) {
  357. PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_ALLOC_CONFIG);
  358. if (CmResourceList) {
  359. status = ZwSetValueKey(
  360. handle,
  361. &unicodeName,
  362. TITLE_INDEX_VALUE,
  363. REG_RESOURCE_LIST,
  364. CmResourceList,
  365. Length
  366. );
  367. } else {
  368. status = ZwDeleteValueKey(handle, &unicodeName);
  369. }
  370. ZwClose(handle);
  371. }
  372. }
  373. PiUnlockPnpRegistry();
  374. return status;
  375. }