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.

508 lines
15 KiB

  1. /*++
  2. Copyright (c) 1995-2000 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. pnpstart.c
  6. Abstract:
  7. This module implements new Plug-And-Play driver entries and IRPs.
  8. Author:
  9. Shie-Lin Tzong (shielint) June-16-1995
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. */
  14. #include "pnpmgrp.h"
  15. #pragma hdrstop
  16. #ifdef POOL_TAGGING
  17. #undef ExAllocatePool
  18. #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'ddpP')
  19. #endif
  20. typedef struct _DEVICE_LIST_CONTEXT {
  21. ULONG DeviceCount;
  22. BOOLEAN Reallocation;
  23. PDEVICE_OBJECT DeviceList[1];
  24. } DEVICE_LIST_CONTEXT, *PDEVICE_LIST_CONTEXT;
  25. NTSTATUS
  26. IopAssignResourcesToDevices (
  27. IN ULONG DeviceCount,
  28. IN PIOP_RESOURCE_REQUEST RequestTable,
  29. IN BOOLEAN DoBootConfigs,
  30. OUT PBOOLEAN RebalancePerformed
  31. );
  32. NTSTATUS
  33. IopGetDriverDeviceList(
  34. IN PDRIVER_OBJECT DriverObject,
  35. OUT PDEVICE_LIST_CONTEXT *DeviceList
  36. );
  37. NTSTATUS
  38. IopProcessAssignResourcesWorker(
  39. IN PDEVICE_NODE DeviceNode,
  40. IN PVOID Context
  41. );
  42. #ifdef ALLOC_PRAGMA
  43. #pragma alloc_text(PAGE, IopAssignResourcesToDevices)
  44. #pragma alloc_text(PAGE, IopProcessAssignResources)
  45. #pragma alloc_text(PAGE, IopProcessAssignResourcesWorker)
  46. #pragma alloc_text(PAGE, IopWriteAllocatedResourcesToRegistry)
  47. #endif // ALLOC_PRAGMA
  48. //
  49. // The following routines should be removed once the real
  50. // Resource Assign code is done.
  51. //
  52. NTSTATUS
  53. IopAssignResourcesToDevices(
  54. IN ULONG DeviceCount,
  55. IN OUT PIOP_RESOURCE_REQUEST RequestTable,
  56. IN BOOLEAN DoBootConfigs,
  57. OUT PBOOLEAN RebalancePerformed
  58. )
  59. /*++
  60. Routine Description:
  61. This routine takes an input array of IOP_RESOURCE_REQUEST structures, and
  62. allocates resource for the physical device object specified in
  63. the structure. The allocated resources are automatically recorded
  64. in the registry.
  65. Arguments:
  66. DeviceCount - Supplies the number of device objects whom we need to
  67. allocate resource to. That is the number of entries
  68. in the RequestTable.
  69. RequestTable - Supplies an array of IOP_RESOURCE_REQUEST structures which
  70. contains the Physical device object to allocate resource to.
  71. Upon entry, the ResourceAssignment pointer is NULL and on
  72. return the allocated resource is returned via the this pointer.
  73. DoBootConfigs - Allow assignment of BOOT configs.
  74. Return Value:
  75. The status returned is the final completion status of the operation.
  76. NOTE:
  77. If NTSTATUS_SUCCESS is returned, the resource allocation for *all* the devices
  78. specified is succeeded. Otherwise, one or more are failed and caller must
  79. examine the ResourceAssignment pointer in each IOP_RESOURCE_REQUEST structure to
  80. determine which devices failed and which succeeded.
  81. --*/
  82. {
  83. NTSTATUS status;
  84. ULONG i;
  85. PAGED_CODE();
  86. ASSERT(DeviceCount != 0);
  87. for (i = 0; i < DeviceCount; i++) {
  88. //
  89. // Initialize table entry.
  90. //
  91. if (PpCallerInitializesRequestTable == TRUE) {
  92. RequestTable[i].Position = i;
  93. }
  94. RequestTable[i].ResourceAssignment = NULL;
  95. RequestTable[i].Status = 0;
  96. RequestTable[i].Flags = 0;
  97. RequestTable[i].AllocationType = ArbiterRequestPnpEnumerated;
  98. if (((PDEVICE_NODE)(RequestTable[i].PhysicalDevice->DeviceObjectExtension->DeviceNode))->Flags & DNF_MADEUP) {
  99. ULONG reportedDevice = 0;
  100. HANDLE hInstance;
  101. status = IopDeviceObjectToDeviceInstance(RequestTable[i].PhysicalDevice, &hInstance, KEY_READ);
  102. if (NT_SUCCESS(status)) {
  103. ULONG resultSize = 0;
  104. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
  105. UNICODE_STRING unicodeString;
  106. PiWstrToUnicodeString(&unicodeString, REGSTR_VALUE_DEVICE_REPORTED);
  107. status = ZwQueryValueKey( hInstance,
  108. &unicodeString,
  109. KeyValuePartialInformation,
  110. (PVOID)buffer,
  111. sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG),
  112. &resultSize);
  113. if (NT_SUCCESS(status)) {
  114. reportedDevice = *(PULONG)(((PKEY_VALUE_PARTIAL_INFORMATION)buffer)->Data);
  115. }
  116. ZwClose(hInstance);
  117. }
  118. //
  119. // Change the AllocationType for reported devices.
  120. //
  121. if (reportedDevice) {
  122. RequestTable[i].AllocationType = ArbiterRequestLegacyReported;
  123. }
  124. }
  125. RequestTable[i].ResourceRequirements = NULL;
  126. }
  127. //
  128. // Allocate memory to build a IOP_ASSIGN table to call IopAllocateResources()
  129. //
  130. status = IopAllocateResources( &DeviceCount,
  131. &RequestTable,
  132. FALSE,
  133. DoBootConfigs,
  134. RebalancePerformed);
  135. return status;
  136. }
  137. BOOLEAN
  138. IopProcessAssignResources(
  139. IN PDEVICE_NODE DeviceNode,
  140. IN BOOLEAN Reallocation,
  141. OUT BOOLEAN *RebalancePerformed
  142. )
  143. /*++
  144. Routine Description:
  145. This function attempts to assign resources to device under the subtree on
  146. which AddDevice has been performed. Prior to the completion of all Boot Bus
  147. Extenders in the system, this routine attempts allocation first so that devices
  148. with no requirements and no boot config get processed. If there are no such devices,
  149. then it attempts to allocate resources for devices with boot config. If there are no
  150. devices with boot config, then other devices (requirements but no boot config)
  151. get processed. During later part of boot, it attempts allocation only once
  152. (since we should have already reserved all the boot configs).
  153. Parameters:
  154. DeviceNode - specifies the root of the subtree under which resources will be
  155. allocated.
  156. Reallocation - if TRUE, we will attempt allocation for devices with resource conflict
  157. problem in addition to other devices.
  158. RebalancePerformed - recieves whether a rebalance was successfully comp[eted.
  159. Return Value:
  160. TRUE if resources got assigned to any device, otherwise FALSE.
  161. --*/
  162. {
  163. PDEVICE_NODE deviceNode;
  164. PDEVICE_LIST_CONTEXT context;
  165. BOOLEAN resourcesAssigned, tryAgain;
  166. ULONG count, i, attempt, maxAttempts;
  167. PIOP_RESOURCE_REQUEST requestTable;
  168. PAGED_CODE();
  169. resourcesAssigned = FALSE;
  170. tryAgain = TRUE;
  171. maxAttempts = (IopBootConfigsReserved)? 1 : 2;
  172. for (attempt = 0; !resourcesAssigned && tryAgain && attempt < maxAttempts; attempt++) {
  173. tryAgain = FALSE;
  174. //
  175. // Allocate and init memory for resource context
  176. //
  177. context = (PDEVICE_LIST_CONTEXT) ExAllocatePool(
  178. PagedPool,
  179. sizeof(DEVICE_LIST_CONTEXT) +
  180. sizeof(PDEVICE_OBJECT) * IopNumberDeviceNodes
  181. );
  182. if (!context) {
  183. return FALSE;
  184. }
  185. context->DeviceCount = 0;
  186. context->Reallocation = Reallocation;
  187. //
  188. // Parse the device node subtree to determine which devices need resources
  189. //
  190. IopProcessAssignResourcesWorker(DeviceNode, context);
  191. count = context->DeviceCount;
  192. if (count == 0) {
  193. ExFreePool(context);
  194. return FALSE;
  195. }
  196. //
  197. // Need to assign resources to devices. Build the resource request table and call
  198. // resource assignment routine.
  199. //
  200. requestTable = (PIOP_RESOURCE_REQUEST) ExAllocatePool(
  201. PagedPool,
  202. sizeof(IOP_RESOURCE_REQUEST) * count
  203. );
  204. if (requestTable) {
  205. for (i = 0; i < count; i++) {
  206. requestTable[i].Priority = 0;
  207. requestTable[i].PhysicalDevice = context->DeviceList[i];
  208. }
  209. //
  210. // Assign resources
  211. //
  212. IopAssignResourcesToDevices(
  213. count,
  214. requestTable,
  215. (attempt == 0) ? IopBootConfigsReserved : TRUE,
  216. RebalancePerformed
  217. );
  218. //
  219. // Check the results
  220. //
  221. for (i = 0; i < count; i++) {
  222. deviceNode = (PDEVICE_NODE)
  223. requestTable[i].PhysicalDevice->DeviceObjectExtension->DeviceNode;
  224. if (NT_SUCCESS(requestTable[i].Status)) {
  225. if (requestTable[i].ResourceAssignment) {
  226. deviceNode->ResourceList = requestTable[i].ResourceAssignment;
  227. deviceNode->ResourceListTranslated = requestTable[i].TranslatedResourceAssignment;
  228. } else {
  229. deviceNode->Flags |= DNF_NO_RESOURCE_REQUIRED;
  230. }
  231. PipSetDevNodeState(deviceNode, DeviceNodeResourcesAssigned, NULL);
  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. }