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.

4952 lines
143 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. ppcontrol.c
  5. Abstract:
  6. User-mode -> Kernel-mode PnP Manager control routines.
  7. Author:
  8. Lonny McMichael (lonnym) 02/14/95
  9. Revision History:
  10. --*/
  11. #include "pnpmgrp.h"
  12. #include "picontrol.h"
  13. #define _APPHELP_CACHE_INIT_
  14. #include "ahcache.h"
  15. #pragma hdrstop
  16. //
  17. // Global driver object that is used by calls to NtPlugPlayControl
  18. // with control type of PlugPlayControlDetectResourceConflict.
  19. //
  20. #ifdef ALLOC_DATA_PRAGMA
  21. #pragma data_seg("PAGEDATA")
  22. #endif
  23. //
  24. // Define mask of devnode flags that are settable from user-mode via the
  25. // NtPlugPlayControl, PlugPlayControlGetDeviceStatus (which is a misnomer,
  26. // since it can perform both gets and sets).
  27. //
  28. #define DEVICE_NODE_SETTABLE_FLAG_BITS (DNF_HAS_PROBLEM | \
  29. DNF_HAS_PRIVATE_PROBLEM \
  30. )
  31. NTSTATUS
  32. PiControlCopyUserModeCallersBuffer(
  33. IN PVOID Destination,
  34. IN PVOID Src,
  35. IN ULONG Length,
  36. IN ULONG Alignment,
  37. IN KPROCESSOR_MODE CallerMode,
  38. IN BOOLEAN ReadUserModeBuffer
  39. );
  40. NTSTATUS
  41. PiGetInterfaceDeviceAlias(
  42. IN PUNICODE_STRING SymbolicLinkName,
  43. IN LPGUID AliasClassGuid,
  44. OUT PWSTR AliasSymbolicLinkName,
  45. IN OUT PULONG AliasSymbolicLinkNameLength
  46. );
  47. NTSTATUS
  48. PiGenerateLegacyDeviceInstance(
  49. IN PUNICODE_STRING ServiceKeyName,
  50. OUT PWSTR DeviceInstance,
  51. IN OUT PULONG DeviceInstanceLength
  52. );
  53. NTSTATUS
  54. PiQueueQueryAndRemoveEvent(
  55. IN PUNICODE_STRING DeviceInstance,
  56. IN PPNP_VETO_TYPE VetoType,
  57. IN LPWSTR VetoName,
  58. IN PULONG VetoNameLength,
  59. IN ULONG Flags
  60. );
  61. NTSTATUS
  62. PiQueueDeviceRequest(
  63. IN PUNICODE_STRING DeviceInstance,
  64. IN DEVICE_REQUEST_TYPE RequestType,
  65. IN ULONG Flags,
  66. IN BOOLEAN Synchronous
  67. );
  68. NTSTATUS
  69. PiInitializeDevice(
  70. IN PUNICODE_STRING DeviceInstance
  71. );
  72. NTSTATUS
  73. PiDetectResourceConflict(
  74. IN PCM_RESOURCE_LIST ResourceList,
  75. IN ULONG ResourceListSize
  76. );
  77. NTSTATUS
  78. PiGetInterfaceDeviceList(
  79. IN GUID *InterfaceGuid,
  80. IN PUNICODE_STRING DeviceInstance,
  81. IN ULONG Flags,
  82. OUT PWSTR InterfaceList,
  83. IN OUT PULONG InterfaceListSize
  84. );
  85. NTSTATUS
  86. PiDeviceClassAssociation(
  87. IN PUNICODE_STRING DeviceInstance,
  88. IN GUID * ClassGuid,
  89. IN PUNICODE_STRING Reference, OPTIONAL
  90. IN OUT PWSTR SymbolicLink,
  91. IN OUT PULONG SymbolicLinkLength,
  92. IN BOOLEAN Register
  93. );
  94. NTSTATUS
  95. PiGetRelatedDevice(
  96. IN PUNICODE_STRING TargetDeviceInstance,
  97. OUT LPWSTR RelatedDeviceInstance,
  98. IN OUT PULONG RelatedDeviceInstanceLength,
  99. IN ULONG Relation
  100. );
  101. NTSTATUS
  102. PiQueryDeviceRelations(
  103. IN PUNICODE_STRING DeviceInstance,
  104. IN PNP_QUERY_RELATION Operation,
  105. OUT PULONG BufferLength,
  106. OUT LPWSTR Buffer
  107. );
  108. DEVICE_RELATION_TYPE
  109. PiDeviceRelationType(
  110. PNP_QUERY_RELATION Operation
  111. );
  112. NTSTATUS
  113. PiControlGetBlockedDriverData(
  114. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  115. IN OUT PPLUGPLAY_CONTROL_BLOCKED_DRIVER_DATA BlockedDriverData,
  116. IN ULONG PnPControlDataLength,
  117. IN KPROCESSOR_MODE CallerMode
  118. );
  119. #ifdef ALLOC_PRAGMA
  120. #pragma alloc_text(PAGELK, PpShutdownSystem) // this gets called after paging shutdown
  121. #pragma alloc_text(PAGE, NtPlugPlayControl)
  122. #pragma alloc_text(PAGE, PiControlMakeUserModeCallersCopy)
  123. #pragma alloc_text(PAGE, PiControlCopyUserModeCallersBuffer)
  124. #pragma alloc_text(PAGE, PiGetInterfaceDeviceAlias)
  125. #pragma alloc_text(PAGE, PiGenerateLegacyDeviceInstance)
  126. #pragma alloc_text(PAGE, PiQueueQueryAndRemoveEvent)
  127. #pragma alloc_text(PAGE, PiInitializeDevice)
  128. #pragma alloc_text(PAGE, PiDetectResourceConflict)
  129. #pragma alloc_text(PAGE, PiGetInterfaceDeviceList)
  130. #pragma alloc_text(PAGE, PiDeviceClassAssociation)
  131. #pragma alloc_text(PAGE, PiGetRelatedDevice)
  132. #pragma alloc_text(PAGE, PiQueryDeviceRelations)
  133. #pragma alloc_text(PAGE, PiDeviceRelationType)
  134. #pragma alloc_text(PAGE, PiControlGetUserFlagsFromDeviceNode)
  135. #pragma alloc_text(PAGE, PiQueueDeviceRequest)
  136. #pragma alloc_text(PAGE, PiControlEnumerateDevice)
  137. #pragma alloc_text(PAGE, PiControlRegisterNewDevice)
  138. #pragma alloc_text(PAGE, PiControlDeregisterDevice)
  139. #pragma alloc_text(PAGE, PiControlInitializeDevice)
  140. #pragma alloc_text(PAGE, PiControlStartDevice)
  141. #pragma alloc_text(PAGE, PiControlResetDevice)
  142. #pragma alloc_text(PAGE, PiControlQueryAndRemoveDevice)
  143. #pragma alloc_text(PAGE, PiControlUserResponse)
  144. #pragma alloc_text(PAGE, PiControlGenerateLegacyDevice)
  145. #pragma alloc_text(PAGE, PiControlGetInterfaceDeviceList)
  146. #pragma alloc_text(PAGE, PiControlGetPropertyData)
  147. #pragma alloc_text(PAGE, PiControlDeviceClassAssociation)
  148. #pragma alloc_text(PAGE, PiControlGetRelatedDevice)
  149. #pragma alloc_text(PAGE, PiControlGetInterfaceDeviceAlias)
  150. #pragma alloc_text(PAGE, PiControlGetSetDeviceStatus)
  151. #pragma alloc_text(PAGE, PiControlGetDeviceDepth)
  152. #pragma alloc_text(PAGE, PiControlQueryDeviceRelations)
  153. #pragma alloc_text(PAGE, PiControlQueryTargetDeviceRelation)
  154. #pragma alloc_text(PAGE, PiControlQueryConflictList)
  155. #pragma alloc_text(PAGE, PiControlGetDevicePowerData)
  156. #pragma alloc_text(PAGE, PiControlRetrieveDockData)
  157. #pragma alloc_text(PAGE, PiControlHaltDevice)
  158. #pragma alloc_text(PAGE, PiControlGetBlockedDriverData)
  159. #if DBG
  160. #pragma alloc_text(PAGE, PiControlExceptionFilter)
  161. #endif
  162. #endif // ALLOC_PRAGMA
  163. //
  164. // This table contains handlers for all the messages coming from the
  165. // umpnpmgr.dll.
  166. //
  167. PLUGPLAY_CONTROL_HANDLER_DATA PlugPlayHandlerTable[] = {
  168. { PlugPlayControlEnumerateDevice,
  169. sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA),
  170. PiControlEnumerateDevice },
  171. { PlugPlayControlRegisterNewDevice,
  172. sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA),
  173. PiControlRegisterNewDevice },
  174. { PlugPlayControlDeregisterDevice,
  175. sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA),
  176. PiControlDeregisterDevice },
  177. { PlugPlayControlInitializeDevice,
  178. sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA),
  179. PiControlInitializeDevice },
  180. { PlugPlayControlStartDevice,
  181. sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA),
  182. PiControlStartDevice },
  183. { PlugPlayControlUnlockDevice,
  184. sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA),
  185. NULL },
  186. { PlugPlayControlQueryAndRemoveDevice,
  187. sizeof(PLUGPLAY_CONTROL_QUERY_AND_REMOVE_DATA),
  188. PiControlQueryAndRemoveDevice },
  189. { PlugPlayControlUserResponse,
  190. sizeof(PLUGPLAY_CONTROL_USER_RESPONSE_DATA),
  191. PiControlUserResponse },
  192. { PlugPlayControlGenerateLegacyDevice,
  193. sizeof(PLUGPLAY_CONTROL_LEGACY_DEVGEN_DATA),
  194. PiControlGenerateLegacyDevice },
  195. { PlugPlayControlGetInterfaceDeviceList,
  196. sizeof(PLUGPLAY_CONTROL_INTERFACE_LIST_DATA),
  197. PiControlGetInterfaceDeviceList },
  198. { PlugPlayControlProperty,
  199. sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA),
  200. PiControlGetPropertyData },
  201. { PlugPlayControlDeviceClassAssociation,
  202. sizeof(PLUGPLAY_CONTROL_CLASS_ASSOCIATION_DATA),
  203. PiControlDeviceClassAssociation },
  204. { PlugPlayControlGetRelatedDevice,
  205. sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA),
  206. PiControlGetRelatedDevice },
  207. { PlugPlayControlGetInterfaceDeviceAlias,
  208. sizeof(PLUGPLAY_CONTROL_INTERFACE_ALIAS_DATA),
  209. PiControlGetInterfaceDeviceAlias },
  210. { PlugPlayControlDeviceStatus,
  211. sizeof(PLUGPLAY_CONTROL_STATUS_DATA),
  212. PiControlGetSetDeviceStatus },
  213. { PlugPlayControlGetDeviceDepth,
  214. sizeof(PLUGPLAY_CONTROL_DEPTH_DATA),
  215. PiControlGetDeviceDepth },
  216. { PlugPlayControlQueryDeviceRelations,
  217. sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA),
  218. PiControlQueryDeviceRelations },
  219. { PlugPlayControlTargetDeviceRelation,
  220. sizeof(PLUGPLAY_CONTROL_TARGET_RELATION_DATA),
  221. PiControlQueryTargetDeviceRelation },
  222. { PlugPlayControlQueryConflictList,
  223. sizeof(PLUGPLAY_CONTROL_CONFLICT_DATA),
  224. PiControlQueryConflictList },
  225. { PlugPlayControlRetrieveDock,
  226. sizeof(PLUGPLAY_CONTROL_RETRIEVE_DOCK_DATA),
  227. PiControlRetrieveDockData },
  228. { PlugPlayControlResetDevice,
  229. sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA),
  230. PiControlResetDevice },
  231. { PlugPlayControlHaltDevice,
  232. sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA),
  233. PiControlHaltDevice },
  234. { PlugPlayControlGetBlockedDriverList,
  235. sizeof(PLUGPLAY_CONTROL_BLOCKED_DRIVER_DATA),
  236. PiControlGetBlockedDriverData },
  237. { MaxPlugPlayControl,
  238. 0,
  239. NULL }
  240. };
  241. NTSTATUS
  242. NtPlugPlayControl(
  243. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  244. IN OUT PVOID PnPControlData,
  245. IN ULONG PnPControlDataLength
  246. )
  247. /*++
  248. Routine Description:
  249. This Plug and Play Manager API provides a mechanism for the user-mode
  250. PnP Manager to control the activity of its kernel-mode counterpart.
  251. Arguments:
  252. PnPControlClass - Specifies what action to perform.
  253. PnPControlData - Supplies a pointer to data specific to this action.
  254. PnPControlDataLength - Specifies the size, in bytes, of the buffer pointed
  255. to by PnPControlData
  256. Return Value:
  257. NT status code indicating success or failure. Set of possible return
  258. values includes the following:
  259. STATUS_SUCCESS - normal, successful completion.
  260. STATUS_INVALID_PARAMETER_1 - The PnPControlClass parameter did not
  261. specify a valid control class.
  262. STATUS_INVALID_PARAMETER_MIX - The value of the PnPControlDataLength
  263. parameter did not match the length required for the control
  264. class requested by the PnPControlClass parameter.
  265. STATUS_BUFFER_TOO_SMALL - The size of the supplied output buffer is not
  266. large enough to hold the output generated by this control class.
  267. STATUS_ACCESS_VIOLATION - One of the following pointers specified
  268. an invalid address: (1) the PnPControlData buffer pointer,
  269. (2) some pointer contained in the PnPControlData buffer.
  270. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources exist
  271. for this request to complete.
  272. --*/
  273. {
  274. NTSTATUS status, tempStatus;
  275. KPROCESSOR_MODE previousMode;
  276. ULONG index;
  277. PPLUGPLAY_CONTROL_HANDLER_DATA handlerData;
  278. PVOID controlDataSnapshot;
  279. PAGED_CODE();
  280. //
  281. // Get previous processor mode and probe arguments if necessary.
  282. //
  283. previousMode = KeGetPreviousMode();
  284. if (previousMode != KernelMode) {
  285. //
  286. // Does the caller have "trusted computer base" privilge?
  287. //
  288. if (!SeSinglePrivilegeCheck(SeTcbPrivilege, UserMode)) {
  289. IopDbgPrint((IOP_IOAPI_WARNING_LEVEL,
  290. "NtPlugPlayControl: SecurityCheck failed\n"));
  291. return STATUS_PRIVILEGE_NOT_HELD;
  292. }
  293. }
  294. //
  295. // Look through the table to find the appropriate handler. Note that
  296. // the control class *should* be an index into the table itself.
  297. //
  298. index = (ULONG)PnPControlClass;
  299. handlerData = NULL;
  300. if (index < MaxPlugPlayControl) {
  301. if (PlugPlayHandlerTable[index].ControlCode == PnPControlClass) {
  302. handlerData = &PlugPlayHandlerTable[index];
  303. } else {
  304. //
  305. // Someone broke the table.
  306. //
  307. IopDbgPrint((IOP_IOAPI_ERROR_LEVEL,
  308. "NtPlugPlayControl: Lookup table isn't ordered correctly (entry %d)!\n",
  309. PnPControlClass));
  310. ASSERT(PlugPlayHandlerTable[index].ControlCode == PnPControlClass);
  311. return STATUS_INTERNAL_ERROR;
  312. }
  313. }
  314. //
  315. // Do we have handler data?
  316. //
  317. if (handlerData == NULL) {
  318. //
  319. // Invalid control class.
  320. //
  321. IopDbgPrint((IOP_IOAPI_ERROR_LEVEL,
  322. "NtPlugPlayControl: Unknown control class, Class = %d, Size = %d\n",
  323. PnPControlClass,
  324. PnPControlDataLength));
  325. return STATUS_INVALID_PARAMETER_1;
  326. }
  327. //
  328. // No control function means not implemented.
  329. //
  330. if (handlerData->ControlFunction == NULL) {
  331. return STATUS_NOT_IMPLEMENTED;
  332. }
  333. //
  334. // Check the data size.
  335. //
  336. if (handlerData->ControlDataSize != PnPControlDataLength) {
  337. IopDbgPrint((IOP_IOAPI_ERROR_LEVEL,
  338. "NtPlugPlayControl: Invalid size for control, Class = %d, Size = %d\n",
  339. PnPControlClass,
  340. PnPControlDataLength));
  341. return STATUS_INVALID_PARAMETER_MIX;
  342. }
  343. //
  344. // Make copy of caller's buffer.
  345. //
  346. status = PiControlMakeUserModeCallersCopy(
  347. &controlDataSnapshot,
  348. PnPControlData,
  349. PnPControlDataLength,
  350. sizeof(ULONG),
  351. previousMode,
  352. TRUE
  353. );
  354. if (!NT_SUCCESS(status)) {
  355. return status;
  356. }
  357. //
  358. // Invoke the handler.
  359. //
  360. status = handlerData->ControlFunction(
  361. PnPControlClass,
  362. controlDataSnapshot,
  363. PnPControlDataLength,
  364. previousMode
  365. );
  366. //
  367. // Copy the buffer if the operation was successful or the value is
  368. // a warning like STATUS_BUFFER_OVERFLOW.
  369. //
  370. // ISSUE - 2000/09/11 - Misused STATUS code
  371. // Here we hack around the fact that we've been returning
  372. // STATUS_BUFFER_TOO_SMALL instead of STATUS_BUFFER_OVERFLOW. This
  373. // should be fixed here and in UMPNPMGR.
  374. //
  375. if ((!NT_ERROR(status)) || (status == STATUS_BUFFER_TOO_SMALL)) {
  376. //
  377. // Copy result back into caller's buffer.
  378. //
  379. tempStatus = PiControlMakeUserModeCallersCopy(
  380. &PnPControlData,
  381. controlDataSnapshot,
  382. PnPControlDataLength,
  383. sizeof(ULONG),
  384. previousMode,
  385. FALSE
  386. );
  387. if (!NT_SUCCESS(tempStatus)) {
  388. status = tempStatus;
  389. }
  390. }
  391. //
  392. // Free buffer allocated for user mode caller.
  393. //
  394. PiControlFreeUserModeCallersBuffer(previousMode, controlDataSnapshot);
  395. return status;
  396. }
  397. NTSTATUS
  398. PiControlCopyUserModeCallersBuffer(
  399. IN PVOID Destination,
  400. IN PVOID Src,
  401. IN ULONG Length,
  402. IN ULONG Alignment,
  403. IN KPROCESSOR_MODE CallerMode,
  404. IN BOOLEAN ReadUserModeBuffer
  405. )
  406. {
  407. NTSTATUS status;
  408. PAGED_CODE();
  409. status = STATUS_SUCCESS;
  410. if (CallerMode == KernelMode) {
  411. //
  412. // Copy from Src to Destination.
  413. //
  414. RtlCopyMemory(
  415. Destination,
  416. Src,
  417. Length);
  418. return status;
  419. }
  420. try {
  421. if (ReadUserModeBuffer) {
  422. //
  423. // Probe user-mode buffer before reading from it.
  424. //
  425. ProbeForRead(
  426. Src,
  427. Length,
  428. Alignment);
  429. } else {
  430. //
  431. // Probe user-mode buffer before writing to it.
  432. //
  433. ProbeForWrite(
  434. Destination,
  435. Length,
  436. Alignment);
  437. }
  438. //
  439. // Copy from Src to Destination.
  440. //
  441. RtlCopyMemory(
  442. Destination,
  443. Src,
  444. Length);
  445. } except(PiControlExceptionFilter(GetExceptionInformation())) {
  446. status = GetExceptionCode();
  447. IopDbgPrint((IOP_IOAPI_ERROR_LEVEL,
  448. "PiControlMakeUserModeCallersCopy: Exception 0x%08x copying data to or from user's buffer\n", status));
  449. }
  450. return status;
  451. }
  452. NTSTATUS
  453. PiControlMakeUserModeCallersCopy(
  454. IN OUT PVOID *Destination,
  455. IN PVOID Src,
  456. IN ULONG Length,
  457. IN ULONG Alignment,
  458. IN KPROCESSOR_MODE CallerMode,
  459. IN BOOLEAN AllocateDestination
  460. )
  461. /*++
  462. Routine Description:
  463. This routine copies data from and to a callers (potentially UserMode) buffer
  464. after appropriate probing and under try-except.
  465. If CallerMode is KernelMode, then it does not do any copy.
  466. If CallerMode is not KernelMode and AllocateDestination is TRUE, Src is a user
  467. mode buffer that will be probed. We will also allocate the Destination buffer and
  468. make a copy of the user mode buffer.
  469. If CallerMode is not KernelMode and AllocateDestination is FALSE, Src is the kernel
  470. mode buffer whose data needs to be copied into Destination.
  471. Arguments:
  472. Destination - Receives pointer to buffer allocated if AllocateDestination is TRUE,
  473. else contains the pointer to the buffer where data needs to be copied.
  474. Src - Pointer to data to be copied.
  475. Length - Length of data to be copied in bytes.
  476. Alignment - Alignment for probing user mode buffer.
  477. CallerMode - KernelMode\UserMode
  478. AllocateDestination - If TRUE, allocate Length sized buffer and return the pointer
  479. in Destination.
  480. Return Value:
  481. A NTSTATUS code indicating success or cause of failure.
  482. --*/
  483. {
  484. NTSTATUS status;
  485. PAGED_CODE();
  486. if (CallerMode == KernelMode) {
  487. //
  488. // We really dont need to call this function when CallerMode == KernelMode but
  489. // we do so that the callee does not have to special case.
  490. //
  491. *Destination = Src;
  492. return STATUS_SUCCESS;
  493. }
  494. if (Length == 0) {
  495. *Destination = NULL;
  496. return STATUS_SUCCESS;
  497. }
  498. if (AllocateDestination) {
  499. //
  500. // Allocate kernel mode buffer to copy user data.
  501. //
  502. *Destination = ExAllocatePoolWithQuota(
  503. PagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
  504. Length);
  505. if (*Destination == NULL) {
  506. return STATUS_INSUFFICIENT_RESOURCES;
  507. }
  508. }
  509. status = STATUS_SUCCESS;
  510. if (*Destination) {
  511. status = PiControlCopyUserModeCallersBuffer(
  512. *Destination,
  513. Src,
  514. Length,
  515. Alignment,
  516. CallerMode,
  517. AllocateDestination);
  518. if (!NT_SUCCESS(status)) {
  519. if (AllocateDestination == TRUE) {
  520. ExFreePool(*Destination);
  521. *Destination = NULL;
  522. }
  523. }
  524. }
  525. //
  526. // Return final status.
  527. //
  528. return status;
  529. }
  530. NTSTATUS
  531. PiGetInterfaceDeviceAlias(
  532. IN PUNICODE_STRING SymbolicLinkName,
  533. IN LPGUID AliasClassGuid,
  534. OUT PWSTR AliasSymbolicLinkName,
  535. IN OUT PULONG AliasSymbolicLinkNameLength
  536. )
  537. /*++
  538. Routine Description:
  539. This routine retrieves the interface device of the specified class that aliases
  540. a particular interface device. See IoGetAliasForDeviceClassAssociation for
  541. more details.
  542. Arguments:
  543. SymbolicLinkName - Supplies the name of the interface device whose alias is to
  544. be retrieved.
  545. AliasClassGuid - Supplies a pointer to the GUID representing the interface class
  546. in which an alias of SymbolicLinkName is to be found.
  547. AliasSymbolicLinkName - Supplies a character buffer that, upon success, receives
  548. the name of the alias interface device.
  549. AliasSymbolicLinkNameLength - Supplies the length, in bytes, of the
  550. AliasSymbolicLinkName character buffer.
  551. RequiredLength - Supplies the address of a variable that will be filled in with
  552. the number of bytes (including terminating NULL) required to store the
  553. interface device name in the AliasSymbolicLinkName buffer. This will be
  554. filled in upon successful return, or when the return is STATUS_BUFFER_TOO_SMALL.
  555. Return Value:
  556. A NTSTATUS code indicating success or cause of failure.
  557. --*/
  558. {
  559. NTSTATUS status;
  560. UNICODE_STRING aliasString;
  561. PAGED_CODE();
  562. status = IoGetDeviceInterfaceAlias( SymbolicLinkName,
  563. AliasClassGuid,
  564. &aliasString);
  565. if (NT_SUCCESS(status)) {
  566. if (aliasString.Length < *AliasSymbolicLinkNameLength) {
  567. RtlCopyMemory(AliasSymbolicLinkName, aliasString.Buffer, aliasString.Length);
  568. *(PWCHAR)((PUCHAR)AliasSymbolicLinkName + aliasString.Length) = L'\0';
  569. *AliasSymbolicLinkNameLength = aliasString.Length;
  570. } else {
  571. *AliasSymbolicLinkNameLength = aliasString.Length + sizeof(UNICODE_NULL);
  572. status = STATUS_BUFFER_TOO_SMALL;
  573. }
  574. ExFreePool(aliasString.Buffer);
  575. }
  576. return status;
  577. }
  578. NTSTATUS
  579. PiGenerateLegacyDeviceInstance(
  580. IN PUNICODE_STRING ServiceKeyName,
  581. OUT PWSTR DeviceInstance,
  582. IN OUT PULONG DeviceInstanceLength
  583. )
  584. /*++
  585. Routine Description:
  586. This routine creates a new instance node under System\Enum\Root\LEGACY_<Name>
  587. key and all the required default value entries. Also a value entry under
  588. Service\ServiceKeyName\Enum is created to point to the newly created madeup
  589. entry. A handle and the keyname of the new key are returned to caller.
  590. Caller must free the unicode string when he is done with it.
  591. Arguments:
  592. ServiceKeyName - Supplies a pointer to the name of the subkey in the
  593. system service list (HKEY_LOCAL_MACHINE\CurrentControlSet\Services)
  594. that caused the driver to load.
  595. DeviceInstance - Supplies a pointer to the character buffer that receives the
  596. newly-generated device instance name.
  597. DeviceInstanceLength - Supplies the size, in bytes, of the DeviceInstance
  598. buffer.
  599. Return Value:
  600. A NTSTATUS code.
  601. If the legacy device instance exists already, this function returns success.
  602. --*/
  603. {
  604. NTSTATUS status;
  605. HANDLE handle;
  606. ULONG junk;
  607. UNICODE_STRING tempUnicodeString;
  608. PAGED_CODE();
  609. PiLockPnpRegistry(FALSE);
  610. status = PipCreateMadeupNode(ServiceKeyName,
  611. &handle,
  612. &tempUnicodeString,
  613. &junk,
  614. TRUE
  615. );
  616. if (NT_SUCCESS(status)) {
  617. //
  618. // We have successfully retrieved the newly-generated device instance name.
  619. // Now store it in the supplied buffer.
  620. //
  621. ZwClose(handle);
  622. if (tempUnicodeString.Length < *DeviceInstanceLength) {
  623. RtlCopyMemory(DeviceInstance,
  624. tempUnicodeString.Buffer,
  625. tempUnicodeString.Length);
  626. *(PWCHAR)((PUCHAR)DeviceInstance + tempUnicodeString.Length) = L'\0';
  627. *DeviceInstanceLength = tempUnicodeString.Length;
  628. } else {
  629. *DeviceInstanceLength = tempUnicodeString.Length + sizeof(UNICODE_NULL);
  630. status = STATUS_BUFFER_TOO_SMALL;
  631. }
  632. RtlFreeUnicodeString(&tempUnicodeString);
  633. }
  634. PiUnlockPnpRegistry();
  635. return status;
  636. }
  637. NTSTATUS
  638. PiQueueQueryAndRemoveEvent(
  639. IN PUNICODE_STRING DeviceInstance,
  640. IN PPNP_VETO_TYPE VetoType,
  641. IN LPWSTR VetoName,
  642. IN PULONG VetoNameLength,
  643. IN ULONG Flags
  644. )
  645. /*++
  646. Routine Description:
  647. This routine queues an event to handle the specified operation later in
  648. the context of a system thread. There is one master event queue and all
  649. events are handled in the order they were submitted.
  650. This routine also handles user-mode requests to eject the device specified
  651. in DeviceInstance. If the device's capabilities report the device
  652. ejectable or lockable then it is handled by the same code that processes
  653. IoRequestDeviceEject, otherwise the driver stack is removed and the device
  654. node is marked with the problem CM_PROB_DEVICE_NOT_THERE which prevents it
  655. from being reenumerated until the device is physically removed. This later
  656. method is used primarily for things like PCCARD devices.
  657. Arguments:
  658. DeviceInstance - Supplies the device instance name of the device that is
  659. the target of the event.
  660. EventGuid - This is the GUID that uniquely identifies the type of event.
  661. Synchronous - This is a boolean flag indicating whether the action should
  662. be performed synchronously or asynchronously (synchronous if TRUE).
  663. Return Value:
  664. A NTSTATUS code.
  665. --*/
  666. {
  667. NTSTATUS status = STATUS_SUCCESS;
  668. PDEVICE_OBJECT deviceObject = NULL;
  669. PDEVICE_NODE deviceNode = NULL;
  670. UNICODE_STRING vetoNameString;
  671. PUNICODE_STRING vetoNameStringPtr;
  672. BOOLEAN noRestart, doEject, onlyRestartRelations;
  673. ULONG problem;
  674. KEVENT userEvent;
  675. ULONG eventResult;
  676. PAGED_CODE();
  677. deviceObject = IopDeviceObjectFromDeviceInstance(DeviceInstance);
  678. if (!deviceObject) {
  679. status = STATUS_NO_SUCH_DEVICE;
  680. goto Clean1;
  681. }
  682. //
  683. // Retrieve the device node for this device object.
  684. //
  685. deviceNode = (PDEVICE_NODE)deviceObject->DeviceObjectExtension->DeviceNode;
  686. if (!deviceNode) {
  687. status = STATUS_NO_SUCH_DEVICE;
  688. goto Clean1;
  689. }
  690. if (deviceNode == IopRootDeviceNode) {
  691. status = STATUS_ACCESS_DENIED;
  692. goto Clean1;
  693. }
  694. vetoNameString.Length = 0;
  695. vetoNameString.MaximumLength = (USHORT)(*VetoNameLength);
  696. if (vetoNameString.MaximumLength != 0) {
  697. vetoNameString.Buffer = ExAllocatePool(PagedPool, vetoNameString.MaximumLength);
  698. if (vetoNameString.Buffer == NULL) {
  699. vetoNameString.MaximumLength = 0;
  700. }
  701. vetoNameStringPtr = &vetoNameString;
  702. } else {
  703. vetoNameString.Buffer = NULL;
  704. vetoNameStringPtr = NULL;
  705. }
  706. //
  707. // Do preprocessing of device node before queueing notification.
  708. //
  709. if (Flags & (PNP_QUERY_AND_REMOVE_DISABLE |
  710. PNP_QUERY_AND_REMOVE_EJECT_DEVICE)) {
  711. noRestart = TRUE;
  712. } else {
  713. noRestart = FALSE;
  714. }
  715. //
  716. // Nobody has ever used this flag. We should not see it here, and we ignore
  717. // it if we do see it.
  718. //
  719. ASSERT(!(Flags & PNP_QUERY_AND_REMOVE_UNINSTALL));
  720. onlyRestartRelations = FALSE;
  721. if (Flags & PNP_QUERY_AND_REMOVE_DISABLE) {
  722. //
  723. // this particular problem may cause a
  724. // "NonDisableable" Veto
  725. //
  726. problem = CM_PROB_DISABLED;
  727. doEject = FALSE;
  728. } else if (Flags & PNP_QUERY_AND_REMOVE_EJECT_DEVICE) {
  729. problem = CM_PROB_HELD_FOR_EJECT;
  730. doEject = TRUE;
  731. } else {
  732. problem = CM_PROB_WILL_BE_REMOVED;
  733. doEject = FALSE;
  734. if (Flags & PNP_QUERY_AND_REMOVE_NO_RESTART) {
  735. onlyRestartRelations = TRUE;
  736. }
  737. }
  738. //
  739. // Queue this device event
  740. //
  741. KeInitializeEvent(&userEvent, NotificationEvent, FALSE);
  742. //
  743. // Queue the event, this call will return immediately. Note that status
  744. // is the status of the PpSetTargetDeviceChange while result is the
  745. // outcome of the actual event.
  746. //
  747. status = PpSetTargetDeviceRemove(deviceObject,
  748. FALSE,
  749. noRestart,
  750. onlyRestartRelations,
  751. doEject,
  752. problem,
  753. &userEvent,
  754. &eventResult,
  755. VetoType,
  756. vetoNameStringPtr);
  757. //
  758. // Drop the ref since there is now one in PpSetTargetDeviceRemove itself.
  759. //
  760. ObDereferenceObject(deviceObject);
  761. deviceObject = NULL;
  762. if (!NT_SUCCESS(status)) {
  763. goto Clean0;
  764. }
  765. //
  766. // Wait for the event we just queued to finish since synchronous operation
  767. // was requested (non alertable wait).
  768. //
  769. // FUTURE ITEM - Use a timeout here?
  770. //
  771. status = KeWaitForSingleObject(&userEvent, Executive, KernelMode, FALSE, NULL);
  772. if (NT_SUCCESS(status)) {
  773. status = eventResult;
  774. }
  775. if (vetoNameString.Length != 0) {
  776. if (vetoNameString.Length >= vetoNameString.MaximumLength) {
  777. vetoNameString.Length--;
  778. }
  779. RtlCopyMemory(VetoName, vetoNameString.Buffer, vetoNameString.Length);
  780. VetoName[ vetoNameString.Length / sizeof(WCHAR) ] = L'\0';
  781. }
  782. if (VetoNameLength != NULL) {
  783. *VetoNameLength = vetoNameString.Length;
  784. }
  785. Clean0:
  786. if (vetoNameString.Buffer != NULL) {
  787. ExFreePool(vetoNameString.Buffer);
  788. }
  789. Clean1:
  790. if (deviceObject) {
  791. ObDereferenceObject(deviceObject);
  792. }
  793. return status;
  794. } // PiQueueDeviceEvent
  795. NTSTATUS
  796. PiInitializeDevice(
  797. IN PUNICODE_STRING DeviceInstance
  798. )
  799. /*++
  800. Routine Description:
  801. This routine creates a devnode for the device instance and performs
  802. any other necessary initialization of the device instance.
  803. Arguments:
  804. DeviceInstance - Supplies the path in the registry (relative to
  805. HKLM\System\Enum) to the device instance to initalize.
  806. Return Value:
  807. NT status code indicating success or failure of this routine.
  808. --*/
  809. {
  810. NTSTATUS status;
  811. UNICODE_STRING serviceName;
  812. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  813. ULONG deviceFlags;
  814. HANDLE hEnum, hDevInst;
  815. PDEVICE_OBJECT deviceObject;
  816. PDEVICE_NODE deviceNode = NULL;
  817. PAGED_CODE();
  818. hEnum = NULL;
  819. hDevInst = NULL;
  820. keyValueInformation = NULL;
  821. //
  822. // Acquire lock on the registry before we do any initialization.
  823. //
  824. PiLockPnpRegistry(TRUE);
  825. deviceObject = IopDeviceObjectFromDeviceInstance(DeviceInstance);
  826. if (deviceObject) {
  827. ObDereferenceObject(deviceObject);
  828. status = STATUS_SUCCESS;
  829. goto Clean0;
  830. }
  831. //
  832. // Open a key to HKLM\SYSTEM\CCC\Enum
  833. //
  834. status = IopOpenRegistryKeyEx( &hEnum,
  835. NULL,
  836. &CmRegistryMachineSystemCurrentControlSetEnumName,
  837. KEY_ALL_ACCESS);
  838. if (!NT_SUCCESS(status)) {
  839. goto Clean0;
  840. }
  841. //
  842. // Open a key to the specified device instance
  843. //
  844. status = IopCreateRegistryKeyEx( &hDevInst,
  845. hEnum,
  846. DeviceInstance,
  847. KEY_ALL_ACCESS,
  848. REG_OPTION_NON_VOLATILE,
  849. NULL);
  850. if (!NT_SUCCESS(status)) {
  851. goto Clean0;
  852. }
  853. //
  854. // We need to propagate the ConfigFlag to problem and values (devnode flags)
  855. //
  856. deviceFlags = 0;
  857. status = IopGetRegistryValue(hDevInst,
  858. REGSTR_VALUE_CONFIG_FLAGS,
  859. &keyValueInformation);
  860. if (NT_SUCCESS(status)) {
  861. if ((keyValueInformation->Type == REG_DWORD) &&
  862. (keyValueInformation->DataLength >= sizeof(ULONG))) {
  863. deviceFlags = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
  864. }
  865. ExFreePool(keyValueInformation);
  866. keyValueInformation = NULL;
  867. }
  868. //
  869. // Get the "Service=" value entry from KeyHandle
  870. //
  871. PiWstrToUnicodeString(&serviceName, NULL);
  872. status = IopGetRegistryValue(hDevInst,
  873. REGSTR_VALUE_SERVICE,
  874. &keyValueInformation);
  875. if (NT_SUCCESS(status)) {
  876. if ((keyValueInformation->Type == REG_SZ) &&
  877. (keyValueInformation->DataLength != 0)) {
  878. //
  879. // Set up ServiceKeyName unicode string
  880. //
  881. IopRegistryDataToUnicodeString(&serviceName,
  882. (PWSTR)KEY_VALUE_DATA(keyValueInformation),
  883. keyValueInformation->DataLength);
  884. }
  885. //
  886. // Do not free keyValueInformation right now (contains Service Name).
  887. //
  888. }
  889. //
  890. // Create madeup PDO and device node to represent the root device.
  891. //
  892. status = IoCreateDevice( IoPnpDriverObject,
  893. 0,
  894. NULL,
  895. FILE_DEVICE_CONTROLLER,
  896. FILE_AUTOGENERATED_DEVICE_NAME,
  897. FALSE,
  898. &deviceObject);
  899. if (!NT_SUCCESS(status)) {
  900. goto Clean0;
  901. }
  902. deviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
  903. status = PipAllocateDeviceNode(deviceObject, &deviceNode);
  904. if (!deviceNode) {
  905. if (status == STATUS_SYSTEM_HIVE_TOO_LARGE) {
  906. status = STATUS_INSUFFICIENT_RESOURCES;
  907. }
  908. goto Clean0;
  909. }
  910. deviceNode->Flags = DNF_MADEUP | DNF_ENUMERATED;
  911. PipSetDevNodeState(deviceNode, DeviceNodeInitialized, NULL);
  912. if (deviceFlags & CONFIGFLAG_REINSTALL) {
  913. PipSetDevNodeProblem(deviceNode, CM_PROB_REINSTALL);
  914. } else if (deviceFlags & CONFIGFLAG_PARTIAL_LOG_CONF) {
  915. PipSetDevNodeProblem(deviceNode, CM_PROB_PARTIAL_LOG_CONF);
  916. }
  917. //
  918. // Make a copy of the device instance path and save it in
  919. // device node.
  920. //
  921. status = PipConcatenateUnicodeStrings(&deviceNode->InstancePath,
  922. DeviceInstance,
  923. NULL);
  924. if (!NT_SUCCESS(status)) {
  925. goto Clean0;
  926. }
  927. if (serviceName.Length != 0) {
  928. //
  929. // Make a copy of the service name and save it in device node.
  930. //
  931. status = PipConcatenateUnicodeStrings(&deviceNode->ServiceName,
  932. &serviceName,
  933. NULL);
  934. } else {
  935. PiWstrToUnicodeString(&deviceNode->ServiceName, NULL);
  936. }
  937. //
  938. // Add an entry into the table to set up a mapping between the DO
  939. // and the instance path.
  940. //
  941. status = IopMapDeviceObjectToDeviceInstance(
  942. deviceNode->PhysicalDeviceObject,
  943. &deviceNode->InstancePath);
  944. if (NT_SUCCESS(status)) {
  945. PpDevNodeInsertIntoTree(IopRootDeviceNode, deviceNode);
  946. //
  947. // Add an event so user-mode will attempt to install this device later.
  948. //
  949. PpSetPlugPlayEvent(&GUID_DEVICE_ENUMERATED,
  950. deviceNode->PhysicalDeviceObject);
  951. }
  952. Clean0:
  953. //
  954. // Clean up.
  955. //
  956. if (!NT_SUCCESS(status)) {
  957. if (deviceObject) {
  958. IoDeleteDevice(deviceObject);
  959. }
  960. }
  961. //
  962. // Release the registry lock.
  963. //
  964. PiUnlockPnpRegistry();
  965. if (keyValueInformation != NULL) {
  966. ExFreePool(keyValueInformation);
  967. }
  968. if (hDevInst) {
  969. ZwClose(hDevInst);
  970. }
  971. if (hEnum) {
  972. ZwClose(hEnum);
  973. }
  974. return status;
  975. } // PiInitializeDevice
  976. NTSTATUS
  977. PiDetectResourceConflict(
  978. IN PCM_RESOURCE_LIST ResourceList,
  979. IN ULONG ResourceListSize
  980. )
  981. /*++
  982. Routine Description:
  983. This routine is invoked to test whether the specified resource
  984. list conflicts with any already assigned resources.
  985. Arguments:
  986. ResourceList - Specifies a resource list buffer.
  987. ResourceListSize - Specifies the size of the resource list buffer.
  988. Return Value:
  989. The function value is an NTSTATUS value; STATUS_SUCCESS indicates
  990. that the resources do not conflict, STATUS_INSUFFICIENT_RESOURCES
  991. indicates that the resource conflict with already assigned
  992. resources (or some other NTSTATUS value may indicate a different
  993. internal error).
  994. --*/
  995. {
  996. OBJECT_ATTRIBUTES objectAttributes;
  997. HANDLE handle;
  998. PWSTR buffer;
  999. NTSTATUS status;
  1000. UNICODE_STRING DriverName;
  1001. ULONG i;
  1002. BOOLEAN bTemp;
  1003. CM_RESOURCE_LIST EmptyResourceList;
  1004. static PDRIVER_OBJECT driverObject = NULL;
  1005. PAGED_CODE();
  1006. if (driverObject == NULL) {
  1007. //
  1008. // Driver object has not been created yet, do that now.
  1009. //
  1010. PiWstrToUnicodeString(&DriverName, L"\\Device\\PlugPlay");
  1011. //
  1012. // Begin by creating the permanent driver object.
  1013. //
  1014. InitializeObjectAttributes(&objectAttributes,
  1015. &DriverName,
  1016. OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
  1017. (HANDLE)NULL,
  1018. (PSECURITY_DESCRIPTOR)NULL);
  1019. //
  1020. // Specify "KernelMode" here since it refers to the source of
  1021. // the objectAttributes buffer, not the previous operating system
  1022. // mode.
  1023. //
  1024. status = ObCreateObject(KernelMode,
  1025. IoDriverObjectType,
  1026. &objectAttributes,
  1027. KernelMode,
  1028. (PVOID)NULL,
  1029. (ULONG)(sizeof(DRIVER_OBJECT) + sizeof(DRIVER_EXTENSION)),
  1030. 0,
  1031. 0,
  1032. (PVOID)&driverObject);
  1033. if (!NT_SUCCESS(status)) {
  1034. return status;
  1035. }
  1036. //
  1037. // Initialize the driver object.
  1038. //
  1039. RtlZeroMemory(driverObject,
  1040. sizeof(DRIVER_OBJECT) + sizeof(DRIVER_EXTENSION));
  1041. driverObject->DriverExtension = (PDRIVER_EXTENSION)(driverObject + 1);
  1042. driverObject->DriverExtension->DriverObject = driverObject;
  1043. for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
  1044. driverObject->MajorFunction[i] = NULL; // OK???
  1045. }
  1046. driverObject->Type = IO_TYPE_DRIVER;
  1047. driverObject->Size = sizeof(DRIVER_OBJECT);
  1048. driverObject->DriverInit = NULL;
  1049. //
  1050. // Insert the driver object into the object table.
  1051. //
  1052. status = ObInsertObject(driverObject,
  1053. NULL,
  1054. FILE_READ_DATA,
  1055. 0,
  1056. (PVOID *)NULL,
  1057. &handle);
  1058. if (!NT_SUCCESS(status)) {
  1059. //
  1060. // Object is dereferenced by the object manager if insert fails.
  1061. //
  1062. return status;
  1063. }
  1064. //
  1065. // Save the name of the driver so that it can be easily located by functions
  1066. // such as error logging.
  1067. //
  1068. buffer = ExAllocatePool(PagedPool, DriverName.MaximumLength + 2);
  1069. if (buffer) {
  1070. driverObject->DriverName.Buffer = buffer;
  1071. driverObject->DriverName.MaximumLength = DriverName.MaximumLength;
  1072. driverObject->DriverName.Length = DriverName.Length;
  1073. RtlCopyMemory(driverObject->DriverName.Buffer,
  1074. DriverName.Buffer,
  1075. DriverName.MaximumLength);
  1076. buffer[DriverName.Length / sizeof(UNICODE_NULL)] = L'\0';
  1077. }
  1078. }
  1079. //
  1080. // Attempt to acquire the resource, if successful, we know the
  1081. // resource is avaiable, overwise assume it conflicts with another
  1082. // devices resource's.
  1083. //
  1084. status = IoReportResourceUsage(NULL,
  1085. driverObject,
  1086. ResourceList,
  1087. ResourceListSize,
  1088. NULL,
  1089. NULL,
  1090. 0,
  1091. FALSE,
  1092. &bTemp);
  1093. if (NT_SUCCESS(status)) {
  1094. //
  1095. // Clear any resources that might have been assigned to my fake device.
  1096. //
  1097. RtlZeroMemory(&EmptyResourceList, sizeof(CM_RESOURCE_LIST));
  1098. IoReportResourceUsage(NULL,
  1099. driverObject,
  1100. &EmptyResourceList,
  1101. sizeof(CM_RESOURCE_LIST),
  1102. NULL,
  1103. NULL,
  1104. 0,
  1105. FALSE,
  1106. &bTemp);
  1107. }
  1108. if (status == STATUS_CONFLICTING_ADDRESSES) {
  1109. status = STATUS_INSUFFICIENT_RESOURCES;
  1110. }
  1111. return status;
  1112. } // PiDetectResourceConflict
  1113. NTSTATUS
  1114. PiGetInterfaceDeviceList(
  1115. IN GUID *InterfaceGuid,
  1116. IN PUNICODE_STRING DeviceInstance,
  1117. IN ULONG Flags,
  1118. OUT PWSTR InterfaceList,
  1119. IN OUT PULONG InterfaceListSize
  1120. )
  1121. /*++
  1122. Routine Description:
  1123. This routine is invoked to return an interface device list based on
  1124. the specified interface device guid class and optional device instance.
  1125. Arguments:
  1126. Return Value:
  1127. The function value is an NTSTATUS.
  1128. --*/
  1129. {
  1130. NTSTATUS status;
  1131. PWSTR tempBuffer = NULL;
  1132. ULONG tempSize = 0;
  1133. PAGED_CODE();
  1134. //
  1135. // Note: This Iop routine allocates a memory buffer and store the
  1136. // interface device list in that buffer. I need to copy it to the
  1137. // users buffer (if any) and then free it before returning.
  1138. //
  1139. if (DeviceInstance->Length == 0) {
  1140. status = IopGetDeviceInterfaces(InterfaceGuid,
  1141. NULL,
  1142. Flags,
  1143. TRUE, // user-mode format
  1144. &tempBuffer,
  1145. &tempSize);
  1146. } else {
  1147. status = IopGetDeviceInterfaces(InterfaceGuid,
  1148. DeviceInstance,
  1149. Flags,
  1150. TRUE, // user-mode format
  1151. &tempBuffer,
  1152. &tempSize);
  1153. }
  1154. if (NT_SUCCESS(status)) {
  1155. if (InterfaceList) {
  1156. //
  1157. // Not just asking for the size, copy the buffer too.
  1158. //
  1159. if (tempSize > *InterfaceListSize) {
  1160. status = STATUS_BUFFER_TOO_SMALL;
  1161. } else {
  1162. RtlCopyMemory(InterfaceList, tempBuffer, tempSize);
  1163. }
  1164. }
  1165. *InterfaceListSize = tempSize;
  1166. ExFreePool(tempBuffer);
  1167. }
  1168. return status;
  1169. } // PiGetInterfaceDeviceList
  1170. NTSTATUS
  1171. PiDeviceClassAssociation(
  1172. IN PUNICODE_STRING DeviceInstance,
  1173. IN GUID * InterfaceGuid,
  1174. IN PUNICODE_STRING Reference, OPTIONAL
  1175. IN OUT LPWSTR SymbolicLink,
  1176. IN OUT PULONG SymbolicLinkLength,
  1177. IN BOOLEAN Register
  1178. )
  1179. {
  1180. NTSTATUS status = STATUS_SUCCESS;
  1181. UNICODE_STRING tempString;
  1182. PAGED_CODE();
  1183. if (Register) {
  1184. //
  1185. // An interface GUID and device instance are required to register a
  1186. // symbolic link.
  1187. //
  1188. if (!ARGUMENT_PRESENT(InterfaceGuid)) {
  1189. return STATUS_INVALID_PARAMETER;
  1190. }
  1191. if ((!ARGUMENT_PRESENT(DeviceInstance)) ||
  1192. (DeviceInstance->Buffer == NULL) ||
  1193. (DeviceInstance->Length == 0)) {
  1194. return STATUS_INVALID_PARAMETER;
  1195. }
  1196. status = IopRegisterDeviceInterface(DeviceInstance,
  1197. InterfaceGuid,
  1198. Reference,
  1199. TRUE, // user-mode format
  1200. &tempString);
  1201. if (NT_SUCCESS(status)) {
  1202. ASSERT(tempString.Buffer);
  1203. if ((tempString.Length + sizeof(UNICODE_NULL)) <= *SymbolicLinkLength) {
  1204. //
  1205. // copy the returned symbolic link to user buffer
  1206. //
  1207. RtlCopyMemory(SymbolicLink, tempString.Buffer, tempString.Length);
  1208. SymbolicLink[tempString.Length / sizeof(WCHAR)] = L'\0';
  1209. *SymbolicLinkLength = tempString.Length + sizeof(UNICODE_NULL);
  1210. } else {
  1211. //
  1212. // return only the length of the registered symbolic link.
  1213. //
  1214. *SymbolicLinkLength = tempString.Length + sizeof(UNICODE_NULL);
  1215. status = STATUS_BUFFER_TOO_SMALL;
  1216. }
  1217. ExFreePool(tempString.Buffer);
  1218. }
  1219. } else {
  1220. //
  1221. // A symbolic link name is required to unregister a device interface.
  1222. //
  1223. if ((!ARGUMENT_PRESENT(SymbolicLink)) ||
  1224. (!ARGUMENT_PRESENT(SymbolicLinkLength)) ||
  1225. (*SymbolicLinkLength == 0)) {
  1226. return STATUS_INVALID_PARAMETER;
  1227. }
  1228. RtlInitUnicodeString(&tempString, SymbolicLink);
  1229. //
  1230. // Unregister any interfaces using this symbolic link
  1231. //
  1232. status = IopUnregisterDeviceInterface(&tempString);
  1233. }
  1234. return status;
  1235. } // PiDeviceClassAssociation
  1236. NTSTATUS
  1237. PiGetRelatedDevice(
  1238. IN PUNICODE_STRING TargetDeviceInstance,
  1239. OUT LPWSTR RelatedDeviceInstance,
  1240. IN OUT PULONG RelatedDeviceInstanceLength,
  1241. IN ULONG Relation
  1242. )
  1243. {
  1244. NTSTATUS status = STATUS_SUCCESS;
  1245. PDEVICE_OBJECT deviceObject, relatedDeviceObject;
  1246. PDEVICE_NODE deviceNode, originalDeviceNode, relatedDeviceNode;
  1247. PAGED_CODE();
  1248. PpDevNodeLockTree(PPL_SIMPLE_READ);
  1249. //
  1250. // Retrieve the PDO from the device instance string.
  1251. //
  1252. deviceObject = IopDeviceObjectFromDeviceInstance(TargetDeviceInstance);
  1253. if (!deviceObject) {
  1254. status = STATUS_NO_SUCH_DEVICE;
  1255. goto Clean0;
  1256. }
  1257. //
  1258. // Retrieve the devnode from the PDO
  1259. //
  1260. deviceNode = (PDEVICE_NODE)deviceObject->DeviceObjectExtension->DeviceNode;
  1261. if (!deviceNode) {
  1262. status = STATUS_NO_SUCH_DEVICE;
  1263. goto Clean0;
  1264. }
  1265. originalDeviceNode = deviceNode;
  1266. if ((deviceNode->State == DeviceNodeDeleted) ||
  1267. (deviceNode->State == DeviceNodeDeletePendingCloses)) {
  1268. status = STATUS_NO_SUCH_DEVICE;
  1269. goto Clean0;
  1270. }
  1271. switch (Relation) {
  1272. case PNP_RELATION_PARENT:
  1273. relatedDeviceNode = deviceNode->Parent;
  1274. break;
  1275. case PNP_RELATION_CHILD:
  1276. relatedDeviceNode = deviceNode->Child;
  1277. if (relatedDeviceNode &&
  1278. PipIsDevNodeProblem(relatedDeviceNode, CM_PROB_DEVICE_NOT_THERE) &&
  1279. (relatedDeviceNode->Flags & DNF_LEGACY_DRIVER)) {
  1280. deviceNode = relatedDeviceNode;
  1281. //
  1282. // Fall through...
  1283. //
  1284. } else {
  1285. break;
  1286. }
  1287. case PNP_RELATION_SIBLING:
  1288. relatedDeviceNode = deviceNode->Sibling;
  1289. while (relatedDeviceNode &&
  1290. PipIsDevNodeProblem(relatedDeviceNode, CM_PROB_DEVICE_NOT_THERE) &&
  1291. (relatedDeviceNode->Flags & DNF_LEGACY_DRIVER)) {
  1292. relatedDeviceNode = relatedDeviceNode->Sibling;
  1293. }
  1294. break;
  1295. default:
  1296. status = STATUS_INVALID_PARAMETER;
  1297. goto Clean0;
  1298. }
  1299. //
  1300. // We now have what we think is the relatedDeviceNode but we need to make
  1301. // sure that it hasn't been uninstalled or had its registry info
  1302. // removed in some other way. Otherwise we won't be able to find its
  1303. // siblings. If we can't map from its InstancePath to a PDO skip it and go
  1304. // on to the next sibling.
  1305. //
  1306. if (Relation != PNP_RELATION_PARENT) {
  1307. PiLockPnpRegistry(FALSE);
  1308. while (relatedDeviceNode) {
  1309. if (relatedDeviceNode->InstancePath.Length != 0) {
  1310. //
  1311. // Retrieve the PDO from the device instance string.
  1312. //
  1313. relatedDeviceObject = IopDeviceObjectFromDeviceInstance(&relatedDeviceNode->InstancePath);
  1314. if (relatedDeviceObject != NULL) {
  1315. ObDereferenceObject(relatedDeviceObject);
  1316. break;
  1317. }
  1318. }
  1319. relatedDeviceNode = relatedDeviceNode->Sibling;
  1320. }
  1321. PiUnlockPnpRegistry();
  1322. }
  1323. if (relatedDeviceNode != NULL) {
  1324. if (*RelatedDeviceInstanceLength > relatedDeviceNode->InstancePath.Length) {
  1325. RtlCopyMemory(RelatedDeviceInstance,
  1326. relatedDeviceNode->InstancePath.Buffer,
  1327. relatedDeviceNode->InstancePath.Length);
  1328. *(PWCHAR)((PUCHAR)RelatedDeviceInstance + relatedDeviceNode->InstancePath.Length) = L'\0';
  1329. *RelatedDeviceInstanceLength = relatedDeviceNode->InstancePath.Length;
  1330. } else {
  1331. *RelatedDeviceInstanceLength = relatedDeviceNode->InstancePath.Length + sizeof(UNICODE_NULL);
  1332. status = STATUS_BUFFER_TOO_SMALL;
  1333. }
  1334. } else {
  1335. status = STATUS_NO_SUCH_DEVICE;
  1336. }
  1337. Clean0:
  1338. PpDevNodeUnlockTree(PPL_SIMPLE_READ);
  1339. if (deviceObject) {
  1340. ObDereferenceObject(deviceObject);
  1341. }
  1342. return status;
  1343. } // PiGetRelatedDevice
  1344. NTSTATUS
  1345. PiQueryDeviceRelations(
  1346. IN PUNICODE_STRING DeviceInstance,
  1347. IN PNP_QUERY_RELATION Operation,
  1348. OUT PULONG BufferLength,
  1349. OUT LPWSTR Buffer
  1350. )
  1351. {
  1352. NTSTATUS status = STATUS_SUCCESS;
  1353. PDEVICE_OBJECT deviceObject = NULL;
  1354. PDEVICE_NODE deviceNode, relatedDeviceNode;
  1355. IO_STACK_LOCATION irpSp;
  1356. PDEVICE_RELATIONS deviceRelations = NULL;
  1357. DEVICE_RELATION_TYPE relationType;
  1358. ULONG length = 0, i;
  1359. ULONG maxCount, currentCount;
  1360. LPWSTR pBuffer;
  1361. PAGED_CODE();
  1362. //
  1363. // Map the private operation code into a DEVICE_RELATION_TYPE enum value.
  1364. //
  1365. relationType = PiDeviceRelationType(Operation);
  1366. if (relationType == (ULONG)-1) {
  1367. return STATUS_INVALID_PARAMETER;
  1368. }
  1369. PpDevNodeLockTree(PPL_SIMPLE_READ);
  1370. //
  1371. // Retrieve the device object from the device instance string.
  1372. //
  1373. deviceObject = IopDeviceObjectFromDeviceInstance(DeviceInstance);
  1374. if (!deviceObject) {
  1375. status = STATUS_NO_SUCH_DEVICE;
  1376. goto Clean0;
  1377. }
  1378. deviceNode = deviceObject->DeviceObjectExtension->DeviceNode;
  1379. ASSERT(deviceNode != NULL);
  1380. //
  1381. // We don't want to bother with things not in the tree...
  1382. //
  1383. if ((deviceNode->State == DeviceNodeDeletePendingCloses) ||
  1384. (deviceNode->State == DeviceNodeDeleted)) {
  1385. status = STATUS_NO_SUCH_DEVICE;
  1386. goto Clean0;
  1387. }
  1388. if (relationType == BusRelations) {
  1389. //
  1390. // Querying the bus relations from the FDO has side effects. Besides
  1391. // we are really interested in the current relations, not those that
  1392. // may be appearing or disappearing.
  1393. //
  1394. //
  1395. // Walk the bus relations list counting the number of children
  1396. //
  1397. maxCount = 0;
  1398. for (relatedDeviceNode = deviceNode->Child;
  1399. relatedDeviceNode != NULL;
  1400. relatedDeviceNode = relatedDeviceNode->Sibling) {
  1401. maxCount++;
  1402. }
  1403. deviceRelations = ExAllocatePool( PagedPool,
  1404. sizeof(DEVICE_RELATIONS) +
  1405. maxCount * sizeof(PDEVICE_OBJECT));
  1406. if (deviceRelations != NULL) {
  1407. deviceRelations->Count = maxCount;
  1408. currentCount = 0;
  1409. //
  1410. // Walk the bus relations list counting the number of relations.
  1411. // Note that we carefully take into account that legacy devnodes
  1412. // can be added to the root totally asynchronously!
  1413. //
  1414. for (relatedDeviceNode = deviceNode->Child;
  1415. ((relatedDeviceNode != NULL) && (currentCount < maxCount));
  1416. relatedDeviceNode = relatedDeviceNode->Sibling) {
  1417. ObReferenceObject(relatedDeviceNode->PhysicalDeviceObject);
  1418. deviceRelations->Objects[currentCount++] =
  1419. relatedDeviceNode->PhysicalDeviceObject;
  1420. }
  1421. ASSERT(currentCount == deviceRelations->Count);
  1422. } else {
  1423. status = STATUS_INSUFFICIENT_RESOURCES;
  1424. }
  1425. } else {
  1426. //
  1427. // Initialize the stack location to pass to IopSynchronousCall()
  1428. //
  1429. RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION));
  1430. //
  1431. // Query the device's relations.
  1432. //
  1433. irpSp.MajorFunction = IRP_MJ_PNP_POWER;
  1434. irpSp.MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
  1435. irpSp.Parameters.QueryDeviceRelations.Type = relationType;
  1436. status = IopSynchronousCall(deviceObject, &irpSp, (PULONG_PTR)&deviceRelations);
  1437. if (!NT_SUCCESS(status)) {
  1438. deviceRelations = NULL;
  1439. }
  1440. }
  1441. //
  1442. // Convert these relation device objects into a multisz list of device instances
  1443. //
  1444. if (deviceRelations && (deviceRelations->Count > 0)) {
  1445. pBuffer = Buffer;
  1446. length = sizeof(UNICODE_NULL); // account for that last extra trailing null
  1447. for (i = 0; i < deviceRelations->Count; i++) {
  1448. relatedDeviceNode = deviceRelations->Objects[i]->DeviceObjectExtension->DeviceNode;
  1449. //
  1450. // The devnode might be NULL if:
  1451. // 1) A driver make a mistake
  1452. // 2) We got back a removal/ejection relation on a newly created
  1453. // PDO that hasn't made it's way back up to the OS (we don't
  1454. // raise the tree lock to BlockReads while an enumeration
  1455. // IRP is outstanding...)
  1456. //
  1457. if (relatedDeviceNode) {
  1458. if (pBuffer) {
  1459. //
  1460. // We're retrieving the device instance strings (not just determining
  1461. // required buffer size). Validate buffer size (including room for
  1462. // null terminator).
  1463. //
  1464. if (*BufferLength < length + relatedDeviceNode->InstancePath.Length + sizeof(UNICODE_NULL)) {
  1465. //
  1466. // ADRIAO ISSUE 02/06/2001 -
  1467. // We aren't returning the proper length here. We
  1468. // need to continue on, copying nothing more yet
  1469. // continuing to calculate the length. This should be
  1470. // fixed this in XP+1, once we have time to verify no
  1471. // one will get an app compat break.
  1472. //
  1473. status = STATUS_BUFFER_TOO_SMALL;
  1474. goto Clean0;
  1475. }
  1476. //
  1477. // Copy this device instance over to the buffer, null terminate it, and
  1478. // update the length used in the buffer so far.
  1479. //
  1480. RtlCopyMemory(pBuffer,
  1481. relatedDeviceNode->InstancePath.Buffer,
  1482. relatedDeviceNode->InstancePath.Length);
  1483. pBuffer += relatedDeviceNode->InstancePath.Length / sizeof(UNICODE_NULL);
  1484. *pBuffer++ = L'\0'; // always need the single-term
  1485. }
  1486. length += relatedDeviceNode->InstancePath.Length + sizeof(UNICODE_NULL);
  1487. }
  1488. ObDereferenceObject(deviceRelations->Objects[i]);
  1489. }
  1490. if (pBuffer) {
  1491. *pBuffer = L'\0'; // This is the last, double-term
  1492. }
  1493. }
  1494. Clean0:
  1495. PpDevNodeUnlockTree(PPL_SIMPLE_READ);
  1496. if (NT_SUCCESS(status)) {
  1497. *BufferLength = length;
  1498. } else {
  1499. *BufferLength = 0;
  1500. }
  1501. if (deviceRelations) {
  1502. ExFreePool(deviceRelations);
  1503. }
  1504. if (deviceObject) {
  1505. ObDereferenceObject(deviceObject);
  1506. }
  1507. return status;
  1508. } // PiQueryDeviceRelations
  1509. DEVICE_RELATION_TYPE
  1510. PiDeviceRelationType(
  1511. PNP_QUERY_RELATION Operation
  1512. )
  1513. /*++
  1514. Routine Description:
  1515. This private routine converts the PNP_QUERY_RELATION enum value into a
  1516. DEVICE_RELATION_TYPE enum value. User-mode and kernel-mode both know about
  1517. PNP_QUERY_RELATION but only kernel-mode knows about DEVICE_RELATION_TYPE.
  1518. Arguments:
  1519. Operation - Specifies a PNP_QUERY_RELATION enum value
  1520. Return Value:
  1521. The function returns a DEVICE_RELATION_TYPE enum value.
  1522. --*/
  1523. {
  1524. PAGED_CODE();
  1525. switch (Operation) {
  1526. case PnpQueryEjectRelations:
  1527. return EjectionRelations;
  1528. case PnpQueryRemovalRelations:
  1529. return RemovalRelations;
  1530. case PnpQueryPowerRelations:
  1531. return PowerRelations;
  1532. case PnpQueryBusRelations:
  1533. return BusRelations;
  1534. default:
  1535. return (ULONG)-1;
  1536. }
  1537. } // PiDeviceRelationType
  1538. VOID
  1539. PiControlGetUserFlagsFromDeviceNode(
  1540. IN PDEVICE_NODE DeviceNode,
  1541. OUT ULONG *StatusFlags
  1542. )
  1543. /*++
  1544. Routine Description:
  1545. This private routine converts the DeviceNode's state into the
  1546. corresponding user-mode StatusFlags.
  1547. Arguments:
  1548. DeviceNode - Specifies the DeviceNode get retrieve user flags for.
  1549. StatusFlags - Receives the corresponding user-mode status flags.
  1550. Return Value:
  1551. The function returns an NTSTATUS value.
  1552. --*/
  1553. {
  1554. ULONG returnedFlags;
  1555. PAGED_CODE();
  1556. //
  1557. // Convert DNF_Xxx flags to the appropriate status and problem values.
  1558. // With problems, order is important since we only keep track of a single
  1559. // problem (use the most recent problem that occured if possible).
  1560. //
  1561. returnedFlags = (DN_NT_DRIVER | DN_NT_ENUMERATOR);
  1562. if (PipAreDriversLoaded(DeviceNode)) {
  1563. returnedFlags |= DN_DRIVER_LOADED;
  1564. }
  1565. if (PipIsDevNodeDNStarted(DeviceNode)) {
  1566. returnedFlags |= DN_STARTED;
  1567. }
  1568. if (DeviceNode->UserFlags & DNUF_WILL_BE_REMOVED) {
  1569. returnedFlags |= DN_WILL_BE_REMOVED;
  1570. }
  1571. if (DeviceNode->UserFlags & DNUF_DONT_SHOW_IN_UI) {
  1572. returnedFlags |= DN_NO_SHOW_IN_DM;
  1573. }
  1574. if (DeviceNode->UserFlags & DNUF_NEED_RESTART) {
  1575. returnedFlags |= DN_NEED_RESTART;
  1576. }
  1577. if (DeviceNode->Flags & DNF_HAS_PRIVATE_PROBLEM) {
  1578. returnedFlags |= DN_PRIVATE_PROBLEM;
  1579. }
  1580. if (DeviceNode->Flags & DNF_HAS_PROBLEM) {
  1581. returnedFlags |= DN_HAS_PROBLEM;
  1582. }
  1583. if ((DeviceNode->Flags & DNF_DRIVER_BLOCKED)) {
  1584. returnedFlags |= DN_DRIVER_BLOCKED;
  1585. }
  1586. if ((DeviceNode->Flags & DNF_LEGACY_DRIVER)) {
  1587. returnedFlags |= DN_LEGACY_DRIVER;
  1588. }
  1589. if ((DeviceNode->Flags & DNF_CHILD_WITH_INVALID_ID)) {
  1590. returnedFlags |= DN_CHILD_WITH_INVALID_ID;
  1591. }
  1592. if (DeviceNode->DisableableDepends == 0) {
  1593. //
  1594. // if there's no reason for us not to be disableable, flag we are disableable
  1595. //
  1596. returnedFlags |= DN_DISABLEABLE;
  1597. }
  1598. //
  1599. // DN_ROOT_ENUMERATED is currently set on umpnpmgr side based on device
  1600. // instance name. We should be able to simply set this flag
  1601. // based on the devnode's LevelNumber except that we don't want BIOS
  1602. // enumerated devices to have the DN_ROOT_ENUMERATED flag even though they
  1603. // are being enumerated by the root enumerator.
  1604. //
  1605. // DN_REMOVABLE - set on umpnpmgr side based on capabilities bits
  1606. // DN_MANUAL - set on umpnpmgr side based on CONFIGFLAG_MANUAL_INSTALL bit.
  1607. // DN_NO_WAIT_INSTALL ???
  1608. *StatusFlags = returnedFlags;
  1609. }
  1610. VOID
  1611. PpShutdownSystem (
  1612. IN BOOLEAN Reboot,
  1613. IN ULONG Phase,
  1614. IN OUT PVOID *Context
  1615. )
  1616. /*++
  1617. Routine Description:
  1618. This routine invokes real code to performs Pnp shutdown preparation.
  1619. This is nonpage code and that's why it is so small.
  1620. Arguments:
  1621. Reboot - specifies if the system is going to reboot.
  1622. Phase - specifies the shutdown phase.
  1623. Context - at phase 0, it supplies a variable to receive the returned context info.
  1624. at phase 1, it supplies a variable to specify the context info.
  1625. Return Value:
  1626. None.
  1627. --*/
  1628. {
  1629. #if defined(_X86_)
  1630. if (Reboot) {
  1631. if (!PpDisableFirmwareMapper) {
  1632. PnPBiosShutdownSystem(Phase, Context);
  1633. }
  1634. }
  1635. #else
  1636. UNREFERENCED_PARAMETER( Reboot );
  1637. UNREFERENCED_PARAMETER( Phase );
  1638. UNREFERENCED_PARAMETER( Context );
  1639. #endif
  1640. if (Phase == 0) {
  1641. ApphelpCacheShutdown(Phase);
  1642. }
  1643. }
  1644. NTSTATUS
  1645. PiQueueDeviceRequest(
  1646. IN PUNICODE_STRING DeviceInstance,
  1647. IN DEVICE_REQUEST_TYPE RequestType,
  1648. IN ULONG Flags,
  1649. IN BOOLEAN Synchronous
  1650. )
  1651. {
  1652. PDEVICE_OBJECT deviceObject;
  1653. PDEVICE_NODE deviceNode;
  1654. KEVENT completionEvent;
  1655. NTSTATUS status;
  1656. PAGED_CODE();
  1657. deviceObject = IopDeviceObjectFromDeviceInstance(DeviceInstance);
  1658. if (!deviceObject) {
  1659. status = STATUS_NO_SUCH_DEVICE;
  1660. goto Clean0;
  1661. }
  1662. deviceNode = (PDEVICE_NODE)deviceObject->DeviceObjectExtension->DeviceNode;
  1663. if (!deviceNode) {
  1664. status = STATUS_NO_SUCH_DEVICE;
  1665. goto Clean0;
  1666. }
  1667. if (Synchronous) {
  1668. KeInitializeEvent(&completionEvent, NotificationEvent, FALSE);
  1669. }
  1670. status = PipRequestDeviceAction( deviceObject,
  1671. RequestType,
  1672. FALSE,
  1673. Flags,
  1674. Synchronous ? &completionEvent : NULL,
  1675. NULL);
  1676. if (NT_SUCCESS(status) && Synchronous) {
  1677. status = KeWaitForSingleObject( &completionEvent,
  1678. Executive,
  1679. KernelMode,
  1680. FALSE,
  1681. NULL);
  1682. }
  1683. Clean0:
  1684. if (deviceObject != NULL) {
  1685. ObDereferenceObject( deviceObject );
  1686. }
  1687. return status;
  1688. }
  1689. NTSTATUS
  1690. PiControlStartDevice(
  1691. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  1692. IN OUT PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA DeviceControlData,
  1693. IN ULONG PnPControlDataLength,
  1694. IN KPROCESSOR_MODE CallerMode
  1695. )
  1696. /*++
  1697. Routine Description:
  1698. This routine starts the specified device instance.
  1699. Arguments:
  1700. PnPControlClass - Should be PlugPlayControlStartDevice.
  1701. DeviceControlData - Points to buffer describing the operation.
  1702. DeviceInstance - Specifies the device instance to be started.
  1703. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)
  1704. CallerMode - Processor mode of caller (UserMode/KernelMode)
  1705. Return Value:
  1706. The function returns an NTSTATUS value.
  1707. --*/
  1708. {
  1709. NTSTATUS status;
  1710. UNICODE_STRING instance;
  1711. PAGED_CODE();
  1712. UNREFERENCED_PARAMETER (PnPControlClass);
  1713. UNREFERENCED_PARAMETER (PnPControlDataLength);
  1714. ASSERT(PnPControlClass == PlugPlayControlStartDevice);
  1715. ASSERT(PnPControlDataLength == sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA));
  1716. //
  1717. // Validate supplied DeviceInstance.
  1718. //
  1719. instance.Length = instance.MaximumLength = DeviceControlData->DeviceInstance.Length;
  1720. if ( instance.Length == 0 ||
  1721. instance.Length > CWC_TO_CB(MAX_DEVICE_ID_LEN) ||
  1722. (instance.Length & 1)) {
  1723. return STATUS_INVALID_PARAMETER;
  1724. }
  1725. //
  1726. // Make a copy of caller supplied DeviceInstance.
  1727. //
  1728. status = PiControlMakeUserModeCallersCopy(
  1729. &instance.Buffer,
  1730. DeviceControlData->DeviceInstance.Buffer,
  1731. instance.Length,
  1732. sizeof(WCHAR),
  1733. CallerMode,
  1734. TRUE);
  1735. if (NT_SUCCESS(status)) {
  1736. //
  1737. // Queue an event to start the device
  1738. //
  1739. status = PiQueueDeviceRequest(
  1740. &instance,
  1741. StartDevice,
  1742. 0,
  1743. TRUE);
  1744. //
  1745. // Free the copy of user mode supplied DeviceInstance.
  1746. //
  1747. PiControlFreeUserModeCallersBuffer(CallerMode, instance.Buffer);
  1748. }
  1749. return status;
  1750. }
  1751. NTSTATUS
  1752. PiControlResetDevice(
  1753. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  1754. IN OUT PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA DeviceControlData,
  1755. IN ULONG PnPControlDataLength,
  1756. IN KPROCESSOR_MODE CallerMode
  1757. )
  1758. /*++
  1759. Routine Description:
  1760. This routine "resets" a devnode, which means bringing it out of the removed
  1761. state without actually starting it.
  1762. Arguments:
  1763. PnPControlClass - Should be PlugPlayControlResetDevice
  1764. ConflictData - Points to buffer that receives conflict data.
  1765. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)
  1766. CallerMode - Processor mode of caller (UserMode/KernelMode)
  1767. Return Value:
  1768. NTSTATUS code (note: must be convertible to user-mode Win32 error)
  1769. --*/
  1770. {
  1771. NTSTATUS status;
  1772. UNICODE_STRING instance;
  1773. UNREFERENCED_PARAMETER (PnPControlDataLength);
  1774. UNREFERENCED_PARAMETER (PnPControlClass);
  1775. instance.Length = instance.MaximumLength = DeviceControlData->DeviceInstance.Length;
  1776. if ( instance.Length == 0 ||
  1777. instance.Length > CWC_TO_CB(MAX_DEVICE_ID_LEN) ||
  1778. (instance.Length & 1)) {
  1779. return STATUS_INVALID_PARAMETER;
  1780. }
  1781. status = PiControlMakeUserModeCallersCopy(
  1782. &instance.Buffer,
  1783. DeviceControlData->DeviceInstance.Buffer,
  1784. DeviceControlData->DeviceInstance.Length,
  1785. sizeof(WCHAR),
  1786. CallerMode,
  1787. TRUE);
  1788. if (NT_SUCCESS(status)) {
  1789. //
  1790. // Queue an event to start the device
  1791. //
  1792. status = PiQueueDeviceRequest(
  1793. &instance,
  1794. ResetDevice,
  1795. 0,
  1796. TRUE);
  1797. PiControlFreeUserModeCallersBuffer(CallerMode, instance.Buffer);
  1798. }
  1799. return status;
  1800. }
  1801. NTSTATUS
  1802. PiControlInitializeDevice(
  1803. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  1804. IN OUT PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA DeviceControlData,
  1805. IN ULONG PnPControlDataLength,
  1806. IN KPROCESSOR_MODE CallerMode
  1807. )
  1808. /*++
  1809. Routine Description:
  1810. This routine initializes the specified device instance.
  1811. Arguments:
  1812. PnPControlClass - Should be PlugPlayControlInitializeDevice.
  1813. DeviceControlData - Points to buffer describing the operation.
  1814. DeviceInstance - Specifies the device instance to be initialized.
  1815. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)
  1816. CallerMode - Processor mode of caller (UserMode/KernelMode)
  1817. Return Value:
  1818. The function returns an NTSTATUS value.
  1819. --*/
  1820. {
  1821. NTSTATUS status;
  1822. UNICODE_STRING instance;
  1823. PAGED_CODE();
  1824. UNREFERENCED_PARAMETER (PnPControlClass);
  1825. UNREFERENCED_PARAMETER (PnPControlDataLength);
  1826. ASSERT(PnPControlClass == PlugPlayControlInitializeDevice);
  1827. ASSERT(PnPControlDataLength == sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA));
  1828. //
  1829. // Make a copy of caller supplied DeviceInstance.
  1830. //
  1831. instance.Length = instance.MaximumLength = DeviceControlData->DeviceInstance.Length;
  1832. if ( instance.Length == 0 ||
  1833. instance.Length > CWC_TO_CB(MAX_DEVICE_ID_LEN) ||
  1834. (instance.Length & 1)) {
  1835. return STATUS_INVALID_PARAMETER;
  1836. }
  1837. status = PiControlMakeUserModeCallersCopy(
  1838. &instance.Buffer,
  1839. DeviceControlData->DeviceInstance.Buffer,
  1840. instance.Length,
  1841. sizeof(WCHAR),
  1842. CallerMode,
  1843. TRUE);
  1844. if (NT_SUCCESS(status)) {
  1845. status = PiInitializeDevice(&instance);
  1846. //
  1847. // Free the copy of user mode supplied DeviceInstance.
  1848. //
  1849. PiControlFreeUserModeCallersBuffer(CallerMode, instance.Buffer);
  1850. }
  1851. return status;
  1852. }
  1853. NTSTATUS
  1854. PiControlDeregisterDevice(
  1855. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  1856. IN OUT PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA DeviceControlData,
  1857. IN ULONG PnPControlDataLength,
  1858. IN KPROCESSOR_MODE CallerMode
  1859. )
  1860. /*++
  1861. Routine Description:
  1862. This routine deregisters the specified device instance.
  1863. Arguments:
  1864. PnPControlClass - Should be PlugPlayControlDeregisterDevice.
  1865. DeviceControlData - Points to buffer describing the operation.
  1866. DeviceInstance - Specifies the device instance to be deregistered.
  1867. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)
  1868. CallerMode - Processor mode of caller (UserMode/KernelMode)
  1869. Return Value:
  1870. The function returns an NTSTATUS value.
  1871. --*/
  1872. {
  1873. NTSTATUS status;
  1874. UNICODE_STRING instance;
  1875. PAGED_CODE();
  1876. UNREFERENCED_PARAMETER (PnPControlClass);
  1877. UNREFERENCED_PARAMETER (PnPControlDataLength);
  1878. ASSERT(PnPControlClass == PlugPlayControlDeregisterDevice);
  1879. ASSERT(PnPControlDataLength == sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA));
  1880. //
  1881. // Make a copy of caller supplied DeviceInstance.
  1882. //
  1883. instance.Length = instance.MaximumLength = DeviceControlData->DeviceInstance.Length;
  1884. if ( instance.Length == 0 ||
  1885. instance.Length > CWC_TO_CB(MAX_DEVICE_ID_LEN) ||
  1886. (instance.Length & 1)) {
  1887. return STATUS_INVALID_PARAMETER;
  1888. }
  1889. status = PiControlMakeUserModeCallersCopy(
  1890. &instance.Buffer,
  1891. DeviceControlData->DeviceInstance.Buffer,
  1892. instance.Length,
  1893. sizeof(WCHAR),
  1894. CallerMode,
  1895. TRUE);
  1896. if (NT_SUCCESS(status)) {
  1897. //
  1898. // Acquire PnP device-specific registry resource for exclusive (read/write) access.
  1899. //
  1900. PiLockPnpRegistry(TRUE);
  1901. status = PiDeviceRegistration(&instance,
  1902. FALSE,
  1903. NULL);
  1904. if (NT_SUCCESS(status)) {
  1905. //
  1906. // Remove all interfaces to this device.
  1907. //
  1908. IopRemoveDeviceInterfaces(&instance);
  1909. }
  1910. PiUnlockPnpRegistry();
  1911. //
  1912. // Free the copy of user mode supplied DeviceInstance.
  1913. //
  1914. PiControlFreeUserModeCallersBuffer(CallerMode, instance.Buffer);
  1915. }
  1916. return status;
  1917. }
  1918. NTSTATUS
  1919. PiControlRegisterNewDevice(
  1920. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  1921. IN OUT PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA DeviceControlData,
  1922. IN ULONG PnPControlDataLength,
  1923. IN KPROCESSOR_MODE CallerMode
  1924. )
  1925. /*++
  1926. Routine Description:
  1927. This routine registers the specified device instance.
  1928. Arguments:
  1929. PnPControlClass - Should be PlugPlayControlRegisterNewDevice.
  1930. DeviceControlData - Points to buffer describing the operation.
  1931. DeviceInstance - Specifies the device instance to be registered.
  1932. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)
  1933. CallerMode - Processor mode of caller (UserMode/KernelMode)
  1934. Return Value:
  1935. The function returns an NTSTATUS value.
  1936. --*/
  1937. {
  1938. NTSTATUS status;
  1939. UNICODE_STRING instance;
  1940. PAGED_CODE();
  1941. UNREFERENCED_PARAMETER (PnPControlClass);
  1942. UNREFERENCED_PARAMETER (PnPControlDataLength);
  1943. ASSERT(PnPControlClass == PlugPlayControlRegisterNewDevice);
  1944. ASSERT(PnPControlDataLength == sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA));
  1945. //
  1946. // Make a copy of caller supplied DeviceInstance.
  1947. //
  1948. instance.Length = instance.MaximumLength = DeviceControlData->DeviceInstance.Length;
  1949. if ( instance.Length == 0 ||
  1950. instance.Length > CWC_TO_CB(MAX_DEVICE_ID_LEN) ||
  1951. (instance.Length & 1)) {
  1952. return STATUS_INVALID_PARAMETER;
  1953. }
  1954. status = PiControlMakeUserModeCallersCopy(
  1955. &instance.Buffer,
  1956. DeviceControlData->DeviceInstance.Buffer,
  1957. instance.Length,
  1958. sizeof(WCHAR),
  1959. CallerMode,
  1960. TRUE);
  1961. if (NT_SUCCESS(status)) {
  1962. status = PpDeviceRegistration(
  1963. &instance,
  1964. TRUE,
  1965. NULL);
  1966. //
  1967. // Free the copy of user mode supplied DeviceInstance.
  1968. //
  1969. PiControlFreeUserModeCallersBuffer(CallerMode, instance.Buffer);
  1970. }
  1971. return status;
  1972. }
  1973. NTSTATUS
  1974. PiControlEnumerateDevice(
  1975. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  1976. IN OUT PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA DeviceControlData,
  1977. IN ULONG PnPControlDataLength,
  1978. IN KPROCESSOR_MODE CallerMode
  1979. )
  1980. /*++
  1981. Routine Description:
  1982. This routine is used to queue reenumeration of the specified device.
  1983. Arguments:
  1984. PnPControlClass - Should be PlugPlayControlEnumerateDevice.
  1985. DeviceControlData - Points to buffer describing the operation.
  1986. DeviceInstance - Specifies the device instance to be reenumerated.
  1987. Flags - Specifies type of reenumeration. The following flags are
  1988. currently defined:
  1989. PNP_ENUMERATE_DEVICE_ONLY - Specifies shallow re-enumeration of
  1990. specified device. If not specified, perfoms reenumeration of
  1991. the entire device subtree rooted at the specified device.
  1992. PNP_ENUMERATE_ASYNCHRONOUS - Specifies that the re-enumeration should
  1993. be done asynchronously.
  1994. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)
  1995. CallerMode - Processor mode of caller (UserMode/KernelMode)
  1996. Return Value:
  1997. The function returns an NTSTATUS value.
  1998. --*/
  1999. {
  2000. NTSTATUS status;
  2001. UNICODE_STRING instance;
  2002. PAGED_CODE();
  2003. UNREFERENCED_PARAMETER (PnPControlClass);
  2004. UNREFERENCED_PARAMETER (PnPControlDataLength);
  2005. ASSERT(PnPControlClass == PlugPlayControlEnumerateDevice);
  2006. ASSERT(PnPControlDataLength == sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA));
  2007. //
  2008. // Make a copy of caller supplied DeviceInstance.
  2009. //
  2010. instance.Length = instance.MaximumLength = DeviceControlData->DeviceInstance.Length;
  2011. if ( instance.Length == 0 ||
  2012. instance.Length > CWC_TO_CB(MAX_DEVICE_ID_LEN) ||
  2013. (instance.Length & 1)) {
  2014. return STATUS_INVALID_PARAMETER;
  2015. }
  2016. status = PiControlMakeUserModeCallersCopy(
  2017. &instance.Buffer,
  2018. DeviceControlData->DeviceInstance.Buffer,
  2019. instance.Length,
  2020. sizeof(WCHAR),
  2021. CallerMode,
  2022. TRUE);
  2023. if (!NT_SUCCESS(status)) {
  2024. return status;
  2025. }
  2026. //
  2027. // Queue a request to enumerate the device
  2028. //
  2029. status = PiQueueDeviceRequest(
  2030. &instance,
  2031. (DeviceControlData->Flags & PNP_ENUMERATE_DEVICE_ONLY) ? ReenumerateDeviceOnly : ReenumerateDeviceTree,
  2032. 0,
  2033. (DeviceControlData->Flags & PNP_ENUMERATE_ASYNCHRONOUS) ? FALSE : TRUE);
  2034. //
  2035. // Free the copy of user mode supplied DeviceInstance.
  2036. //
  2037. PiControlFreeUserModeCallersBuffer(CallerMode, instance.Buffer);
  2038. return status;
  2039. }
  2040. NTSTATUS
  2041. PiControlQueryAndRemoveDevice(
  2042. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  2043. IN OUT PPLUGPLAY_CONTROL_QUERY_AND_REMOVE_DATA QueryAndRemoveData,
  2044. IN ULONG PnPControlDataLength,
  2045. IN KPROCESSOR_MODE CallerMode
  2046. )
  2047. /*++
  2048. Routine Description:
  2049. This routine is used to queue query removal of the specified device.
  2050. Arguments:
  2051. PnPControlClass - Should be PlugPlayControlQueryAndRemoveDevice.
  2052. DeviceControlData - Points to buffer describing the operation.
  2053. DeviceInstance - Specifies the device instance to be query removed.
  2054. VetoType - Vetotype for query remove failure.
  2055. VetoName - Veto information for query remove failure.
  2056. VetoNameLength - Length of VetoName buffer.
  2057. Flags - Remove specific flags.
  2058. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_QUERY_AND_REMOVE_DATA)
  2059. CallerMode - Processor mode of caller (UserMode/KernelMode)
  2060. Return Value:
  2061. The function returns an NTSTATUS value.
  2062. --*/
  2063. {
  2064. NTSTATUS status, tempStatus;
  2065. UNICODE_STRING instance;
  2066. PWCHAR vetoName;
  2067. ULONG vetoNameLength;
  2068. PAGED_CODE();
  2069. UNREFERENCED_PARAMETER (PnPControlClass);
  2070. UNREFERENCED_PARAMETER (PnPControlDataLength);
  2071. ASSERT(PnPControlClass == PlugPlayControlQueryAndRemoveDevice);
  2072. ASSERT(PnPControlDataLength == sizeof(PLUGPLAY_CONTROL_QUERY_AND_REMOVE_DATA));
  2073. //
  2074. // Validate input device instance length.
  2075. //
  2076. instance.Length = instance.MaximumLength = QueryAndRemoveData->DeviceInstance.Length;
  2077. if ( instance.Length == 0 ||
  2078. instance.Length > CWC_TO_CB(MAX_DEVICE_ID_LEN) ||
  2079. (instance.Length & 1)) {
  2080. return STATUS_INVALID_PARAMETER;
  2081. }
  2082. vetoName = NULL;
  2083. instance.Buffer = NULL;
  2084. //
  2085. // Check if the caller wants veto information or not.
  2086. //
  2087. if (QueryAndRemoveData->VetoNameLength && QueryAndRemoveData->VetoName) {
  2088. vetoNameLength = QueryAndRemoveData->VetoNameLength * sizeof(WCHAR);
  2089. } else {
  2090. QueryAndRemoveData->VetoNameLength = vetoNameLength = 0;
  2091. }
  2092. //
  2093. // Allocate our own buffer for veto information for user mode callers,
  2094. // otherwise use the supplied one.
  2095. //
  2096. status = PiControlAllocateBufferForUserModeCaller(
  2097. &vetoName,
  2098. vetoNameLength,
  2099. CallerMode,
  2100. QueryAndRemoveData->VetoName);
  2101. if (!NT_SUCCESS(status)) {
  2102. goto Clean0;
  2103. }
  2104. //
  2105. // Make a copy of caller supplied DeviceInstance.
  2106. //
  2107. status = PiControlMakeUserModeCallersCopy(
  2108. &instance.Buffer,
  2109. QueryAndRemoveData->DeviceInstance.Buffer,
  2110. instance.Length,
  2111. sizeof(WCHAR),
  2112. CallerMode,
  2113. TRUE);
  2114. if (!NT_SUCCESS(status)) {
  2115. goto Clean0;
  2116. }
  2117. //
  2118. // Queue an event to query remove the device
  2119. //
  2120. status = PiQueueQueryAndRemoveEvent(
  2121. &instance,
  2122. &QueryAndRemoveData->VetoType,
  2123. vetoName,
  2124. &vetoNameLength,
  2125. QueryAndRemoveData->Flags);
  2126. if (vetoName) {
  2127. tempStatus = PiControlMakeUserModeCallersCopy(
  2128. &QueryAndRemoveData->VetoName,
  2129. vetoName,
  2130. QueryAndRemoveData->VetoNameLength * sizeof(WCHAR),
  2131. sizeof(WCHAR),
  2132. CallerMode,
  2133. FALSE);
  2134. if (!NT_SUCCESS(tempStatus)) {
  2135. status = tempStatus;
  2136. }
  2137. }
  2138. QueryAndRemoveData->VetoNameLength = vetoNameLength / sizeof(WCHAR);
  2139. //
  2140. // Free vetoName buffer if we allocate one on behalf of user mode caller.
  2141. //
  2142. Clean0:
  2143. PiControlFreeUserModeCallersBuffer(CallerMode, instance.Buffer);
  2144. PiControlFreeUserModeCallersBuffer(CallerMode, vetoName);
  2145. return status;
  2146. }
  2147. NTSTATUS
  2148. PiControlUserResponse(
  2149. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  2150. IN OUT PPLUGPLAY_CONTROL_USER_RESPONSE_DATA UserResponseData,
  2151. IN ULONG PnPControlDataLength,
  2152. IN KPROCESSOR_MODE CallerMode
  2153. )
  2154. /*++
  2155. Routine Description:
  2156. This routine is used to accept user mode response.
  2157. Arguments:
  2158. PnPControlClass - Should be PlugPlayControlUserResponse.
  2159. UserResponseData - Points to buffer describing the operation.
  2160. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_USER_RESPONSE_DATA)
  2161. CallerMode - Processor mode of caller (UserMode/KernelMode)
  2162. Return Value:
  2163. The function returns an NTSTATUS value.
  2164. --*/
  2165. {
  2166. NTSTATUS status;
  2167. PWCHAR vetoName;
  2168. ULONG vetoNameLength;
  2169. PAGED_CODE();
  2170. UNREFERENCED_PARAMETER (PnPControlClass);
  2171. UNREFERENCED_PARAMETER (PnPControlDataLength);
  2172. ASSERT(PnPControlClass == PlugPlayControlUserResponse);
  2173. ASSERT(PnPControlDataLength == sizeof(PLUGPLAY_CONTROL_USER_RESPONSE_DATA));
  2174. if (UserResponseData->VetoNameLength && UserResponseData->VetoName) {
  2175. vetoNameLength = UserResponseData->VetoNameLength * sizeof(WCHAR);
  2176. } else {
  2177. vetoNameLength = 0;
  2178. }
  2179. //
  2180. // Make a copy of callers buffer.
  2181. //
  2182. status = PiControlMakeUserModeCallersCopy(
  2183. &vetoName,
  2184. UserResponseData->VetoName,
  2185. vetoNameLength,
  2186. sizeof(WCHAR),
  2187. CallerMode,
  2188. TRUE);
  2189. if (!NT_SUCCESS(status)) {
  2190. return status;
  2191. }
  2192. //
  2193. // Copy the user response.
  2194. //
  2195. PiUserResponse(
  2196. UserResponseData->Response,
  2197. UserResponseData->VetoType,
  2198. vetoName,
  2199. vetoNameLength);
  2200. PiControlFreeUserModeCallersBuffer(CallerMode, vetoName);
  2201. return STATUS_SUCCESS;
  2202. }
  2203. NTSTATUS
  2204. PiControlGenerateLegacyDevice(
  2205. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  2206. IN OUT PPLUGPLAY_CONTROL_LEGACY_DEVGEN_DATA LegacyDevGenData,
  2207. IN ULONG PnPControlDataLength,
  2208. IN KPROCESSOR_MODE CallerMode
  2209. )
  2210. /*++
  2211. Routine Description:
  2212. This routine is used to generate legacy device instance.
  2213. Arguments:
  2214. PnPControlClass - Should be PlugPlayControlGenerateLegacyDevice.
  2215. UserResponseData - Points to buffer describing the operation.
  2216. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_LEGACY_DEVGEN_DATA)
  2217. CallerMode - Processor mode of caller (UserMode/KernelMode)
  2218. Return Value:
  2219. The function returns an NTSTATUS value.
  2220. --*/
  2221. {
  2222. NTSTATUS status, tempStatus;
  2223. UNICODE_STRING service;
  2224. ULONG instanceLength;
  2225. PWCHAR instance;
  2226. PAGED_CODE();
  2227. UNREFERENCED_PARAMETER (PnPControlClass);
  2228. UNREFERENCED_PARAMETER (PnPControlDataLength);
  2229. ASSERT(PnPControlClass == PlugPlayControlGenerateLegacyDevice);
  2230. ASSERT(PnPControlDataLength == sizeof(PLUGPLAY_CONTROL_LEGACY_DEVGEN_DATA));
  2231. //
  2232. // Validate service name length.
  2233. //
  2234. service.Length = service.MaximumLength = LegacyDevGenData->ServiceName.Length;
  2235. if ( service.Length == 0 ||
  2236. service.Length > CWC_TO_CB(MAX_SERVICE_NAME_LEN) ||
  2237. (service.Length & 1)) {
  2238. return STATUS_INVALID_PARAMETER;
  2239. }
  2240. instance = NULL;
  2241. service.Buffer = NULL;
  2242. instanceLength = LegacyDevGenData->DeviceInstanceLength * sizeof(WCHAR);
  2243. status = PiControlAllocateBufferForUserModeCaller(
  2244. &instance,
  2245. instanceLength,
  2246. CallerMode,
  2247. LegacyDevGenData->DeviceInstance);
  2248. if (!NT_SUCCESS(status)) {
  2249. goto Clean0;
  2250. }
  2251. status = PiControlMakeUserModeCallersCopy(
  2252. &service.Buffer,
  2253. LegacyDevGenData->ServiceName.Buffer,
  2254. service.Length,
  2255. sizeof(WCHAR),
  2256. CallerMode,
  2257. TRUE);
  2258. if (!NT_SUCCESS(status)) {
  2259. goto Clean0;
  2260. }
  2261. status = PiGenerateLegacyDeviceInstance(
  2262. &service,
  2263. instance,
  2264. &instanceLength);
  2265. //
  2266. // Copy the instance and length to the callers buffer.
  2267. //
  2268. if (instance) {
  2269. tempStatus = PiControlMakeUserModeCallersCopy(
  2270. &LegacyDevGenData->DeviceInstance,
  2271. instance,
  2272. LegacyDevGenData->DeviceInstanceLength * sizeof(WCHAR),
  2273. sizeof(WCHAR),
  2274. CallerMode,
  2275. FALSE);
  2276. if (!NT_SUCCESS(tempStatus)) {
  2277. status = tempStatus;
  2278. }
  2279. }
  2280. LegacyDevGenData->DeviceInstanceLength = instanceLength / sizeof(WCHAR);
  2281. //
  2282. // Release any allocated storage.
  2283. //
  2284. Clean0:
  2285. PiControlFreeUserModeCallersBuffer(CallerMode, service.Buffer);
  2286. PiControlFreeUserModeCallersBuffer(CallerMode, instance);
  2287. return status;
  2288. }
  2289. NTSTATUS
  2290. PiControlGetInterfaceDeviceList(
  2291. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  2292. IN OUT PPLUGPLAY_CONTROL_INTERFACE_LIST_DATA InterfaceData,
  2293. IN ULONG PnPControlDataLength,
  2294. IN KPROCESSOR_MODE CallerMode
  2295. )
  2296. /*++
  2297. Routine Description:
  2298. This routine is used to get devices with specified interface.
  2299. Arguments:
  2300. PnPControlClass - Should be PlugPlayControlGetInterfaceDeviceList.
  2301. InterfaceData - Points to buffer describing the operation.
  2302. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_INTERFACE_LIST_DATA)
  2303. CallerMode - Processor mode of caller (UserMode/KernelMode)
  2304. Return Value:
  2305. The function returns an NTSTATUS value.
  2306. --*/
  2307. {
  2308. NTSTATUS status, tempStatus;
  2309. UNICODE_STRING instance;
  2310. PWCHAR list;
  2311. ULONG listSize;
  2312. GUID *guid;
  2313. PAGED_CODE();
  2314. UNREFERENCED_PARAMETER (PnPControlClass);
  2315. UNREFERENCED_PARAMETER (PnPControlDataLength);
  2316. ASSERT(PnPControlClass == PlugPlayControlGetInterfaceDeviceList);
  2317. ASSERT(PnPControlDataLength == sizeof(PLUGPLAY_CONTROL_INTERFACE_LIST_DATA));
  2318. //
  2319. // Validate device instance length if provided.
  2320. //
  2321. if (InterfaceData->DeviceInstance.Buffer) {
  2322. instance.Length = instance.MaximumLength = InterfaceData->DeviceInstance.Length;
  2323. if ( instance.Length == 0 ||
  2324. instance.Length > CWC_TO_CB(MAX_DEVICE_ID_LEN) ||
  2325. (instance.Length & 1)) {
  2326. return STATUS_INVALID_PARAMETER;
  2327. }
  2328. instance.Buffer = NULL;
  2329. } else {
  2330. PiWstrToUnicodeString(&instance, NULL);
  2331. }
  2332. list = NULL;
  2333. guid = NULL;
  2334. //
  2335. // For user mode callers, allocate storage to retrieve the interfacelist.
  2336. //
  2337. if (InterfaceData->InterfaceListSize && InterfaceData->InterfaceList) {
  2338. listSize = InterfaceData->InterfaceListSize * sizeof(WCHAR);
  2339. } else {
  2340. listSize = 0;
  2341. }
  2342. status = PiControlAllocateBufferForUserModeCaller(
  2343. &list,
  2344. listSize,
  2345. CallerMode,
  2346. InterfaceData->InterfaceList);
  2347. if (!NT_SUCCESS(status)) {
  2348. goto Clean0;
  2349. }
  2350. //
  2351. // Copy the user supplied interface GUID.
  2352. //
  2353. status = PiControlMakeUserModeCallersCopy(
  2354. &guid,
  2355. InterfaceData->InterfaceGuid,
  2356. sizeof(GUID),
  2357. sizeof(UCHAR),
  2358. CallerMode,
  2359. TRUE);
  2360. if (!NT_SUCCESS(status)) {
  2361. goto Clean0;
  2362. }
  2363. //
  2364. // Copy the user supplied DeviceInstance.
  2365. //
  2366. if (InterfaceData->DeviceInstance.Buffer) {
  2367. status = PiControlMakeUserModeCallersCopy(
  2368. &instance.Buffer,
  2369. InterfaceData->DeviceInstance.Buffer,
  2370. instance.Length,
  2371. sizeof(WCHAR),
  2372. CallerMode,
  2373. TRUE);
  2374. if (!NT_SUCCESS(status)) {
  2375. goto Clean0;
  2376. }
  2377. }
  2378. //
  2379. // Get the interface list.
  2380. //
  2381. status = PiGetInterfaceDeviceList(
  2382. guid,
  2383. &instance,
  2384. InterfaceData->Flags,
  2385. list,
  2386. &listSize);
  2387. if (list) {
  2388. //
  2389. // Copy the results into the caller's buffer.
  2390. //
  2391. tempStatus = PiControlMakeUserModeCallersCopy(
  2392. &InterfaceData->InterfaceList,
  2393. list,
  2394. InterfaceData->InterfaceListSize * sizeof(WCHAR),
  2395. sizeof(WCHAR),
  2396. CallerMode,
  2397. FALSE);
  2398. if (!NT_SUCCESS(tempStatus)) {
  2399. status = tempStatus;
  2400. }
  2401. }
  2402. InterfaceData->InterfaceListSize = listSize / sizeof(WCHAR);
  2403. Clean0:
  2404. //
  2405. // Clean up.
  2406. //
  2407. PiControlFreeUserModeCallersBuffer(CallerMode, guid);
  2408. PiControlFreeUserModeCallersBuffer(CallerMode, list);
  2409. PiControlFreeUserModeCallersBuffer(CallerMode, instance.Buffer);
  2410. return status;
  2411. }
  2412. NTSTATUS
  2413. PiControlGetPropertyData(
  2414. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  2415. IN OUT PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData,
  2416. IN ULONG PnPControlDataLength,
  2417. IN KPROCESSOR_MODE CallerMode
  2418. )
  2419. /*++
  2420. Routine Description:
  2421. This routine is used to get specified property data.
  2422. Arguments:
  2423. PnPControlClass - Should be PlugPlayControlProperty.
  2424. PropertyData - Points to buffer describing the operation.
  2425. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA)
  2426. CallerMode - Processor mode of caller (UserMode/KernelMode)
  2427. Return Value:
  2428. The function returns an NTSTATUS value.
  2429. --*/
  2430. {
  2431. NTSTATUS status, tempStatus;
  2432. UNICODE_STRING instance;
  2433. PDEVICE_OBJECT deviceObject;
  2434. PDEVICE_NODE deviceNode;
  2435. PVOID buffer;
  2436. ULONG bufferSize;
  2437. DEVICE_REGISTRY_PROPERTY property;
  2438. PWCHAR deviceLocationStrings, p;
  2439. PAGED_CODE();
  2440. UNREFERENCED_PARAMETER (PnPControlClass);
  2441. UNREFERENCED_PARAMETER (PnPControlDataLength);
  2442. ASSERT(PnPControlClass == PlugPlayControlProperty);
  2443. ASSERT(PnPControlDataLength == sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA));
  2444. buffer = NULL;
  2445. instance.Length = instance.MaximumLength = PropertyData->DeviceInstance.Length;
  2446. if ( instance.Length == 0 ||
  2447. instance.Length > CWC_TO_CB(MAX_DEVICE_ID_LEN) ||
  2448. (instance.Length & 1)) {
  2449. return STATUS_INVALID_PARAMETER;
  2450. }
  2451. status = PiControlMakeUserModeCallersCopy(
  2452. &instance.Buffer,
  2453. PropertyData->DeviceInstance.Buffer,
  2454. instance.Length,
  2455. sizeof(WCHAR),
  2456. CallerMode,
  2457. TRUE);
  2458. if (!NT_SUCCESS(status)) {
  2459. return status;
  2460. }
  2461. //
  2462. // Retrieve the physical device object that corresponds to this devinst
  2463. //
  2464. PpDevNodeLockTree(PPL_SIMPLE_READ);
  2465. deviceObject = IopDeviceObjectFromDeviceInstance(&instance);
  2466. PiControlFreeUserModeCallersBuffer(CallerMode, instance.Buffer);
  2467. if (!deviceObject) {
  2468. PpDevNodeUnlockTree(PPL_SIMPLE_READ);
  2469. return STATUS_NO_SUCH_DEVICE;
  2470. }
  2471. //
  2472. // Retrieve the device node for this device object.
  2473. //
  2474. deviceNode = (PDEVICE_NODE)deviceObject->DeviceObjectExtension->DeviceNode;
  2475. if (!deviceNode) {
  2476. status = STATUS_NO_SUCH_DEVICE;
  2477. bufferSize = 0;
  2478. goto Clean0;
  2479. }
  2480. bufferSize = PropertyData->BufferSize;
  2481. status = PiControlAllocateBufferForUserModeCaller(
  2482. &buffer,
  2483. bufferSize,
  2484. CallerMode,
  2485. PropertyData->Buffer
  2486. );
  2487. if (!NT_SUCCESS(status)) {
  2488. goto Clean0;
  2489. }
  2490. switch(PropertyData->PropertyType) {
  2491. case PNP_PROPERTY_PDONAME:
  2492. property = DevicePropertyPhysicalDeviceObjectName;
  2493. break;
  2494. case PNP_PROPERTY_BUSTYPEGUID:
  2495. property = DevicePropertyBusTypeGuid;
  2496. break;
  2497. case PNP_PROPERTY_LEGACYBUSTYPE:
  2498. property = DevicePropertyLegacyBusType;
  2499. break;
  2500. case PNP_PROPERTY_BUSNUMBER:
  2501. property = DevicePropertyBusNumber;
  2502. break;
  2503. case PNP_PROPERTY_ADDRESS:
  2504. property = DevicePropertyAddress;
  2505. break;
  2506. case PNP_PROPERTY_POWER_DATA:
  2507. status = PiControlGetDevicePowerData(
  2508. deviceNode,
  2509. CallerMode,
  2510. bufferSize,
  2511. buffer,
  2512. &PropertyData->BufferSize
  2513. );
  2514. if (status == STATUS_BUFFER_OVERFLOW) {
  2515. //
  2516. // See comment in NtPlugPlayControl.
  2517. //
  2518. status = STATUS_BUFFER_TOO_SMALL;
  2519. }
  2520. goto Clean0;
  2521. case PNP_PROPERTY_REMOVAL_POLICY:
  2522. property = DevicePropertyRemovalPolicy;
  2523. break;
  2524. case PNP_PROPERTY_REMOVAL_POLICY_OVERRIDE:
  2525. status = PiGetDeviceRegistryProperty(
  2526. deviceObject,
  2527. REG_DWORD,
  2528. REGSTR_VALUE_REMOVAL_POLICY,
  2529. NULL,
  2530. buffer,
  2531. &PropertyData->BufferSize
  2532. );
  2533. goto Clean0;
  2534. case PNP_PROPERTY_REMOVAL_POLICY_HARDWARE_DEFAULT:
  2535. if (bufferSize >= sizeof(ULONG)) {
  2536. PpHotSwapGetDevnodeRemovalPolicy(
  2537. deviceNode,
  2538. FALSE, // Include Registry Override
  2539. (PDEVICE_REMOVAL_POLICY) buffer
  2540. );
  2541. status = STATUS_SUCCESS;
  2542. } else {
  2543. status = STATUS_BUFFER_TOO_SMALL;
  2544. }
  2545. PropertyData->BufferSize = sizeof(ULONG);
  2546. goto Clean0;
  2547. case PNP_PROPERTY_INSTALL_STATE:
  2548. property = DevicePropertyInstallState;
  2549. break;
  2550. case PNP_PROPERTY_LOCATION_PATHS:
  2551. deviceLocationStrings = NULL;
  2552. status =
  2553. PpCriticalGetDeviceLocationStrings(
  2554. deviceNode,
  2555. &deviceLocationStrings);
  2556. if (NT_SUCCESS(status)) {
  2557. ASSERT(deviceLocationStrings != NULL);
  2558. //
  2559. // Compute the length of the returned multi-sz list.
  2560. //
  2561. p = deviceLocationStrings;
  2562. while (*p != UNICODE_NULL) {
  2563. p += wcslen(p) + 1;
  2564. }
  2565. //
  2566. // Compute the required buffer length, in bytes.
  2567. //
  2568. PropertyData->BufferSize =
  2569. (ULONG)(((PUCHAR)p - (PUCHAR)deviceLocationStrings) + sizeof(UNICODE_NULL));
  2570. if (PropertyData->BufferSize <= bufferSize) {
  2571. RtlCopyMemory(
  2572. buffer,
  2573. deviceLocationStrings,
  2574. PropertyData->BufferSize);
  2575. } else {
  2576. status = STATUS_BUFFER_TOO_SMALL;
  2577. }
  2578. ExFreePool(deviceLocationStrings);
  2579. }
  2580. goto Clean0;
  2581. default:
  2582. status = STATUS_INVALID_PARAMETER;
  2583. property = DevicePropertyInstallState; // satisfy W4 compiler
  2584. break;
  2585. }
  2586. if (NT_SUCCESS(status)) {
  2587. status = IoGetDeviceProperty( deviceObject,
  2588. property,
  2589. bufferSize,
  2590. buffer,
  2591. &PropertyData->BufferSize
  2592. );
  2593. }
  2594. Clean0:
  2595. PpDevNodeUnlockTree(PPL_SIMPLE_READ);
  2596. ObDereferenceObject(deviceObject);
  2597. tempStatus = PiControlMakeUserModeCallersCopy(
  2598. &PropertyData->Buffer,
  2599. buffer,
  2600. bufferSize,
  2601. sizeof(UCHAR),
  2602. CallerMode,
  2603. FALSE
  2604. );
  2605. if (!NT_SUCCESS(tempStatus)) {
  2606. status = tempStatus;
  2607. }
  2608. PiControlFreeUserModeCallersBuffer(CallerMode, buffer);
  2609. return status;
  2610. }
  2611. NTSTATUS
  2612. PiControlDeviceClassAssociation(
  2613. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  2614. IN OUT PPLUGPLAY_CONTROL_CLASS_ASSOCIATION_DATA AssociationData,
  2615. IN ULONG PnPControlDataLength,
  2616. IN KPROCESSOR_MODE CallerMode
  2617. )
  2618. /*++
  2619. Routine Description:
  2620. This routine is used to get device class association.
  2621. Arguments:
  2622. PnPControlClass - Should be PlugPlayControlDeviceClassAssociation.
  2623. AssociationData - Points to buffer describing the operation.
  2624. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_CLASS_ASSOCIATION_DATA)
  2625. CallerMode - Processor mode of caller (UserMode/KernelMode)
  2626. Return Value:
  2627. The function returns an NTSTATUS value.
  2628. --*/
  2629. {
  2630. NTSTATUS status, tempStatus;
  2631. GUID *guid;
  2632. ULONG symLinkLength;
  2633. PWCHAR symLink;
  2634. UNICODE_STRING instance, reference;
  2635. PAGED_CODE();
  2636. UNREFERENCED_PARAMETER (PnPControlClass);
  2637. UNREFERENCED_PARAMETER (PnPControlDataLength);
  2638. ASSERT(PnPControlClass == PlugPlayControlDeviceClassAssociation);
  2639. ASSERT(PnPControlDataLength == sizeof(PLUGPLAY_CONTROL_CLASS_ASSOCIATION_DATA));
  2640. //
  2641. // Validate lengths of unicode strings.
  2642. //
  2643. if (AssociationData->Register) {
  2644. instance.Length = instance.MaximumLength = AssociationData->DeviceInstance.Length;
  2645. if ( instance.Length == 0 ||
  2646. instance.Length > CWC_TO_CB(MAX_DEVICE_ID_LEN) ||
  2647. (instance.Length & 1)) {
  2648. return STATUS_INVALID_PARAMETER;
  2649. }
  2650. reference.Length = reference.MaximumLength = AssociationData->Reference.Length;
  2651. if (reference.Length & 1) {
  2652. return STATUS_INVALID_PARAMETER;
  2653. }
  2654. }
  2655. symLink = NULL;
  2656. guid = NULL;
  2657. instance.Buffer = NULL;
  2658. reference.Buffer = NULL;
  2659. if (AssociationData->SymLinkLength && AssociationData->SymLink) {
  2660. symLinkLength = AssociationData->SymLinkLength * sizeof(WCHAR);
  2661. } else {
  2662. symLinkLength = 0;
  2663. }
  2664. if (AssociationData->Register) {
  2665. //
  2666. // If registering a device interface, allocate a buffer that is the same
  2667. // size as the one supplied by the caller.
  2668. //
  2669. status = PiControlAllocateBufferForUserModeCaller(
  2670. &symLink,
  2671. symLinkLength,
  2672. CallerMode,
  2673. AssociationData->SymLink);
  2674. if (!NT_SUCCESS(status)) {
  2675. goto Clean0;
  2676. }
  2677. //
  2678. // Copy the user supplied interface GUID, DeviceInstance and Reference.
  2679. //
  2680. status = PiControlMakeUserModeCallersCopy(
  2681. &guid,
  2682. AssociationData->InterfaceGuid,
  2683. AssociationData->InterfaceGuid ? sizeof(GUID) : 0,
  2684. sizeof(UCHAR),
  2685. CallerMode,
  2686. TRUE);
  2687. if (!NT_SUCCESS(status)) {
  2688. goto Clean0;
  2689. }
  2690. status = PiControlMakeUserModeCallersCopy(
  2691. &instance.Buffer,
  2692. AssociationData->DeviceInstance.Buffer,
  2693. AssociationData->DeviceInstance.Length,
  2694. sizeof(WCHAR),
  2695. CallerMode,
  2696. TRUE);
  2697. if (!NT_SUCCESS(status)) {
  2698. goto Clean0;
  2699. }
  2700. status = PiControlMakeUserModeCallersCopy(
  2701. &reference.Buffer,
  2702. AssociationData->Reference.Buffer,
  2703. AssociationData->Reference.Length,
  2704. sizeof(WCHAR),
  2705. CallerMode,
  2706. TRUE);
  2707. if (!NT_SUCCESS(status)) {
  2708. goto Clean0;
  2709. }
  2710. } else {
  2711. //
  2712. // If unregistering a device interface, allocate and copy only the
  2713. // symbolic link path supplied by the caller. Interface GUID,
  2714. // DeviceInstance, and Reference are not required for unregistration.
  2715. //
  2716. if (symLinkLength < sizeof(UNICODE_NULL)) {
  2717. status = STATUS_INVALID_PARAMETER;
  2718. goto Clean0;
  2719. }
  2720. status = PiControlMakeUserModeCallersCopy(
  2721. &symLink,
  2722. AssociationData->SymLink,
  2723. symLinkLength,
  2724. sizeof(WCHAR),
  2725. CallerMode,
  2726. TRUE);
  2727. if (!NT_SUCCESS(status)) {
  2728. goto Clean0;
  2729. }
  2730. //
  2731. // Make sure the user-supplied buffer is NULL terminated, (the length
  2732. // supplied must reflect that).
  2733. //
  2734. symLink[(symLinkLength - sizeof(UNICODE_NULL)) / sizeof(WCHAR)] = L'\0';
  2735. }
  2736. //
  2737. // Register or unregister the device class association.
  2738. //
  2739. status = PiDeviceClassAssociation(
  2740. &instance,
  2741. guid,
  2742. &reference,
  2743. symLink,
  2744. &symLinkLength,
  2745. AssociationData->Register);
  2746. //
  2747. // If a symbolic link was registered, copy the symbolic link name to the
  2748. // caller's buffer.
  2749. //
  2750. if (AssociationData->Register && symLink && NT_SUCCESS(status)) {
  2751. tempStatus = PiControlMakeUserModeCallersCopy(
  2752. &AssociationData->SymLink,
  2753. symLink,
  2754. AssociationData->SymLinkLength * sizeof(WCHAR),
  2755. sizeof(WCHAR),
  2756. CallerMode,
  2757. FALSE);
  2758. if (!NT_SUCCESS(tempStatus)) {
  2759. status = tempStatus;
  2760. }
  2761. }
  2762. //
  2763. // Return the size of the symbolic link name, in characters.
  2764. //
  2765. AssociationData->SymLinkLength = symLinkLength / sizeof(WCHAR);
  2766. Clean0:
  2767. //
  2768. // Clean up.
  2769. //
  2770. PiControlFreeUserModeCallersBuffer(CallerMode, guid);
  2771. PiControlFreeUserModeCallersBuffer(CallerMode, symLink);
  2772. PiControlFreeUserModeCallersBuffer(CallerMode, instance.Buffer);
  2773. PiControlFreeUserModeCallersBuffer(CallerMode, reference.Buffer);
  2774. return status;
  2775. }
  2776. NTSTATUS
  2777. PiControlGetRelatedDevice(
  2778. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  2779. IN OUT PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA RelatedData,
  2780. IN ULONG PnPControlDataLength,
  2781. IN KPROCESSOR_MODE CallerMode
  2782. )
  2783. /*++
  2784. Routine Description:
  2785. This routine is used to get a related device.
  2786. Arguments:
  2787. PnPControlClass - Should be PlugPlayControlGetRelatedDevice.
  2788. RelatedData - Points to buffer describing the operation.
  2789. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA)
  2790. CallerMode - Processor mode of caller (UserMode/KernelMode)
  2791. Return Value:
  2792. The function returns an NTSTATUS value.
  2793. --*/
  2794. {
  2795. NTSTATUS status, tempStatus;
  2796. UNICODE_STRING instance;
  2797. PWCHAR buffer;
  2798. ULONG length;
  2799. PAGED_CODE();
  2800. UNREFERENCED_PARAMETER (PnPControlClass);
  2801. UNREFERENCED_PARAMETER (PnPControlDataLength);
  2802. ASSERT(PnPControlClass == PlugPlayControlGetRelatedDevice);
  2803. ASSERT(PnPControlDataLength == sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA));
  2804. //
  2805. // Validate length of device instance.
  2806. //
  2807. instance.Length = instance.MaximumLength = RelatedData->TargetDeviceInstance.Length;
  2808. if ( instance.Length == 0 ||
  2809. instance.Length > CWC_TO_CB(MAX_DEVICE_ID_LEN) ||
  2810. (instance.Length & 1)) {
  2811. return STATUS_INVALID_PARAMETER;
  2812. }
  2813. buffer = NULL;
  2814. instance.Buffer = NULL;
  2815. if (RelatedData->RelatedDeviceInstance && RelatedData->RelatedDeviceInstanceLength) {
  2816. length = RelatedData->RelatedDeviceInstanceLength * sizeof(WCHAR);
  2817. } else {
  2818. length = 0;
  2819. }
  2820. status = PiControlAllocateBufferForUserModeCaller(
  2821. &buffer,
  2822. length,
  2823. CallerMode,
  2824. RelatedData->RelatedDeviceInstance);
  2825. if (!NT_SUCCESS(status)) {
  2826. goto Clean0;
  2827. }
  2828. status = PiControlMakeUserModeCallersCopy(
  2829. &instance.Buffer,
  2830. RelatedData->TargetDeviceInstance.Buffer,
  2831. instance.Length,
  2832. sizeof(WCHAR),
  2833. CallerMode,
  2834. TRUE);
  2835. if (!NT_SUCCESS(status)) {
  2836. goto Clean0;
  2837. }
  2838. status = PiGetRelatedDevice(
  2839. &instance,
  2840. buffer,
  2841. &length,
  2842. RelatedData->Relation);
  2843. if (buffer) {
  2844. tempStatus = PiControlMakeUserModeCallersCopy(
  2845. &RelatedData->RelatedDeviceInstance,
  2846. buffer,
  2847. RelatedData->RelatedDeviceInstanceLength * sizeof(WCHAR),
  2848. sizeof(WCHAR),
  2849. CallerMode,
  2850. FALSE);
  2851. if (!NT_SUCCESS(tempStatus)) {
  2852. status = tempStatus;
  2853. }
  2854. }
  2855. RelatedData->RelatedDeviceInstanceLength = length / sizeof(WCHAR);
  2856. Clean0:
  2857. //
  2858. // Release any allocated storage.
  2859. //
  2860. PiControlFreeUserModeCallersBuffer(CallerMode, instance.Buffer);
  2861. PiControlFreeUserModeCallersBuffer(CallerMode, buffer);
  2862. return status;
  2863. }
  2864. NTSTATUS
  2865. PiControlGetInterfaceDeviceAlias(
  2866. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  2867. IN OUT PPLUGPLAY_CONTROL_INTERFACE_ALIAS_DATA InterfaceAliasData,
  2868. IN ULONG PnPControlDataLength,
  2869. IN KPROCESSOR_MODE CallerMode
  2870. )
  2871. /*++
  2872. Routine Description:
  2873. This routine is used to get alias for device interface.
  2874. Arguments:
  2875. PnPControlClass - Should be PlugPlayControlGetInterfaceDeviceAlias.
  2876. InterfaceAliasData - Points to buffer describing the operation.
  2877. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_INTERFACE_ALIAS_DATA)
  2878. CallerMode - Processor mode of caller (UserMode/KernelMode)
  2879. Return Value:
  2880. The function returns an NTSTATUS value.
  2881. --*/
  2882. {
  2883. NTSTATUS status, tempStatus;
  2884. PWCHAR alias;
  2885. UNICODE_STRING linkName;
  2886. GUID *guid;
  2887. ULONG aliasLength;
  2888. PAGED_CODE();
  2889. UNREFERENCED_PARAMETER (PnPControlClass);
  2890. UNREFERENCED_PARAMETER (PnPControlDataLength);
  2891. ASSERT(PnPControlClass == PlugPlayControlGetInterfaceDeviceAlias);
  2892. ASSERT(PnPControlDataLength == sizeof(PLUGPLAY_CONTROL_INTERFACE_ALIAS_DATA));
  2893. //
  2894. // Validate length of unicode string.
  2895. //
  2896. linkName.Length = linkName.MaximumLength = InterfaceAliasData->SymbolicLinkName.Length;
  2897. if (linkName.Length & 1) {
  2898. return STATUS_INVALID_PARAMETER;
  2899. }
  2900. alias = NULL;
  2901. guid = NULL;
  2902. linkName.Buffer = NULL;
  2903. if (InterfaceAliasData->AliasSymbolicLinkName && InterfaceAliasData->AliasSymbolicLinkNameLength) {
  2904. aliasLength = InterfaceAliasData->AliasSymbolicLinkNameLength * sizeof(WCHAR);
  2905. } else {
  2906. aliasLength = 0;
  2907. }
  2908. status = PiControlAllocateBufferForUserModeCaller(
  2909. &alias,
  2910. aliasLength,
  2911. CallerMode,
  2912. InterfaceAliasData->AliasSymbolicLinkName);
  2913. if (!NT_SUCCESS(status)) {
  2914. goto Clean0;
  2915. }
  2916. status = PiControlMakeUserModeCallersCopy(
  2917. &guid,
  2918. InterfaceAliasData->AliasClassGuid,
  2919. sizeof(GUID),
  2920. sizeof(UCHAR),
  2921. CallerMode,
  2922. TRUE);
  2923. if (!NT_SUCCESS(status)) {
  2924. goto Clean0;
  2925. }
  2926. status = PiControlMakeUserModeCallersCopy(
  2927. &linkName.Buffer,
  2928. InterfaceAliasData->SymbolicLinkName.Buffer,
  2929. linkName.Length,
  2930. sizeof(WCHAR),
  2931. CallerMode,
  2932. TRUE);
  2933. if (!NT_SUCCESS(status)) {
  2934. goto Clean0;
  2935. }
  2936. status = PiGetInterfaceDeviceAlias(
  2937. &linkName,
  2938. guid,
  2939. alias,
  2940. &aliasLength);
  2941. if (alias) {
  2942. tempStatus = PiControlMakeUserModeCallersCopy(
  2943. &InterfaceAliasData->AliasSymbolicLinkName,
  2944. alias,
  2945. InterfaceAliasData->AliasSymbolicLinkNameLength * sizeof(WCHAR),
  2946. sizeof(WCHAR),
  2947. CallerMode,
  2948. FALSE);
  2949. if (!NT_SUCCESS(tempStatus)) {
  2950. status = tempStatus;
  2951. }
  2952. }
  2953. InterfaceAliasData->AliasSymbolicLinkNameLength = aliasLength / sizeof(WCHAR);
  2954. Clean0:
  2955. //
  2956. // Release any allocated storage.
  2957. //
  2958. PiControlFreeUserModeCallersBuffer(CallerMode, alias);
  2959. PiControlFreeUserModeCallersBuffer(CallerMode, guid);
  2960. PiControlFreeUserModeCallersBuffer(CallerMode, linkName.Buffer);
  2961. return status;
  2962. }
  2963. NTSTATUS
  2964. PiControlGetSetDeviceStatus(
  2965. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  2966. IN OUT PPLUGPLAY_CONTROL_STATUS_DATA StatusData,
  2967. IN ULONG PnPControlDataLength,
  2968. IN KPROCESSOR_MODE CallerMode
  2969. )
  2970. /*++
  2971. Routine Description:
  2972. This routine is used to get the cfgmgr32 status and problem values from
  2973. the specified device instance, or to set the appropriate flags on the devnode
  2974. so that they reflect the status and problem values (used by CM_Set_DevNode_Status).
  2975. Arguments:
  2976. PnPControlClass - Should be PlugPlayControlDeviceStatus.
  2977. StatusData - Points to buffer describing the operation.
  2978. PNP_GET_STATUS:
  2979. DeviceInstance - specifies the device instance name of the devnode
  2980. to return status information for.
  2981. Status - returns the current devnode status.
  2982. Problem - returns the current devnode problem (most recent).
  2983. PNP_SET_STATUS or PNP_CLEAR_STATUS:
  2984. DeviceInstance - specifies the device instance name of the devnode
  2985. whose internal flags are to be modified.
  2986. Status - supplies the address of a variable containing cfgmgr32
  2987. status flags to be translated into their DNF counterparts
  2988. to be set/cleared.
  2989. Problem - supplies the address of a variable containing a cfgmgr32
  2990. problem value to be translated into their DNF
  2991. counterparts to be set/cleared.
  2992. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_STATUS_DATA)
  2993. CallerMode - Processor mode of caller (UserMode/KernelMode)
  2994. Return Value:
  2995. The function returns an NTSTATUS value.
  2996. --*/
  2997. {
  2998. UNICODE_STRING instance;
  2999. PDEVICE_OBJECT deviceObject;
  3000. PDEVICE_NODE deviceNode = NULL;
  3001. NTSTATUS status, result;
  3002. KEVENT event;
  3003. PAGED_CODE();
  3004. UNREFERENCED_PARAMETER (PnPControlClass);
  3005. UNREFERENCED_PARAMETER (PnPControlDataLength);
  3006. ASSERT(PnPControlClass == PlugPlayControlDeviceStatus);
  3007. ASSERT(PnPControlDataLength == sizeof(PLUGPLAY_CONTROL_STATUS_DATA));
  3008. instance.Length = instance.MaximumLength = StatusData->DeviceInstance.Length;
  3009. if ( instance.Length == 0 ||
  3010. instance.Length > CWC_TO_CB(MAX_DEVICE_ID_LEN) ||
  3011. (instance.Length & 1)) {
  3012. return STATUS_INVALID_PARAMETER;
  3013. }
  3014. status = PiControlMakeUserModeCallersCopy(
  3015. &instance.Buffer,
  3016. StatusData->DeviceInstance.Buffer,
  3017. StatusData->DeviceInstance.Length,
  3018. sizeof(WCHAR),
  3019. CallerMode,
  3020. TRUE);
  3021. if (!NT_SUCCESS(status)) {
  3022. return status;
  3023. }
  3024. PpDevNodeLockTree(PPL_SIMPLE_READ);
  3025. //
  3026. // Retrieve the PDO from the device instance string.
  3027. //
  3028. deviceObject = IopDeviceObjectFromDeviceInstance(&instance);
  3029. PiControlFreeUserModeCallersBuffer(CallerMode, instance.Buffer);
  3030. if (deviceObject != NULL) {
  3031. //
  3032. // Retrieve the devnode from the PDO
  3033. //
  3034. deviceNode = (PDEVICE_NODE)deviceObject->DeviceObjectExtension->DeviceNode;
  3035. }
  3036. PpDevNodeUnlockTree(PPL_SIMPLE_READ);
  3037. if (deviceNode == NULL ||
  3038. deviceNode == IopRootDeviceNode) {
  3039. status = STATUS_NO_SUCH_DEVICE;
  3040. goto Clean0;
  3041. }
  3042. switch(StatusData->Operation) {
  3043. case PNP_GET_STATUS:
  3044. //
  3045. // Retrieve the status from the devnode and convert it to a
  3046. // user-mode Win95 style Problem and Status flag values.
  3047. //
  3048. PiControlGetUserFlagsFromDeviceNode(
  3049. deviceNode,
  3050. &StatusData->DeviceStatus);
  3051. StatusData->DeviceProblem = deviceNode->Problem;
  3052. status = STATUS_SUCCESS;
  3053. break;
  3054. case PNP_SET_STATUS:
  3055. KeInitializeEvent(&event, NotificationEvent, FALSE);
  3056. status = PipRequestDeviceAction( deviceObject,
  3057. SetDeviceProblem,
  3058. FALSE,
  3059. (ULONG_PTR) StatusData,
  3060. &event,
  3061. &result);
  3062. if (NT_SUCCESS(status)) {
  3063. status = KeWaitForSingleObject( &event,
  3064. Executive,
  3065. KernelMode,
  3066. FALSE,
  3067. NULL);
  3068. if (status == STATUS_WAIT_0) {
  3069. status = result;
  3070. }
  3071. }
  3072. break;
  3073. case PNP_CLEAR_STATUS:
  3074. KeInitializeEvent(&event, NotificationEvent, FALSE);
  3075. status = PipRequestDeviceAction( deviceObject,
  3076. ClearDeviceProblem,
  3077. FALSE,
  3078. 0,
  3079. &event,
  3080. &result);
  3081. if (NT_SUCCESS(status)) {
  3082. status = KeWaitForSingleObject( &event,
  3083. Executive,
  3084. KernelMode,
  3085. FALSE,
  3086. NULL);
  3087. if (status == STATUS_WAIT_0) {
  3088. status = result;
  3089. }
  3090. }
  3091. break;
  3092. default:
  3093. //
  3094. // ISSUE - 2000/08/16 - ADRIAO: Maintain behavior?
  3095. // We always used to succeed anything not understood!
  3096. //
  3097. status = STATUS_SUCCESS;
  3098. //status = STATUS_INVALID_DEVICE_REQUEST;
  3099. break;
  3100. }
  3101. Clean0:
  3102. //
  3103. // Release any reference to the device object before returning.
  3104. //
  3105. if (deviceObject != NULL) {
  3106. ObDereferenceObject(deviceObject);
  3107. }
  3108. return status;
  3109. }
  3110. NTSTATUS
  3111. PiControlGetDeviceDepth(
  3112. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  3113. IN OUT PPLUGPLAY_CONTROL_DEPTH_DATA DepthData,
  3114. IN ULONG PnPControlDataLength,
  3115. IN KPROCESSOR_MODE CallerMode
  3116. )
  3117. /*++
  3118. Routine Description:
  3119. This routine is invoked to return the depth of a particular devnode (i.e,
  3120. it's depth in the hierarchical devnode tree of parent-child relations).
  3121. Arguments:
  3122. PnPControlClass - Should be PlugPlayControlGetDeviceDepth.
  3123. DepthData - Points to buffer that receives the depth.
  3124. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_DEPTH_DATA)
  3125. CallerMode - Processor mode of caller (UserMode/KernelMode)
  3126. Return Value:
  3127. NTSTATUS code (note: must be convertible to user-mode Win32 error)
  3128. --*/
  3129. {
  3130. NTSTATUS status;
  3131. PDEVICE_OBJECT deviceObject;
  3132. PDEVICE_NODE deviceNode;
  3133. UNICODE_STRING instance;
  3134. PAGED_CODE();
  3135. UNREFERENCED_PARAMETER (PnPControlClass);
  3136. UNREFERENCED_PARAMETER (PnPControlDataLength);
  3137. ASSERT(PnPControlClass == PlugPlayControlGetDeviceDepth);
  3138. ASSERT(PnPControlDataLength == sizeof(PLUGPLAY_CONTROL_DEPTH_DATA));
  3139. instance.Length = instance.MaximumLength = DepthData->DeviceInstance.Length;
  3140. if ( instance.Length == 0 ||
  3141. instance.Length > CWC_TO_CB(MAX_DEVICE_ID_LEN) ||
  3142. (instance.Length & 1)) {
  3143. return STATUS_INVALID_PARAMETER;
  3144. }
  3145. status = PiControlMakeUserModeCallersCopy(
  3146. &instance.Buffer,
  3147. DepthData->DeviceInstance.Buffer,
  3148. DepthData->DeviceInstance.Length,
  3149. sizeof(WCHAR),
  3150. CallerMode,
  3151. TRUE);
  3152. if (!NT_SUCCESS(status)) {
  3153. return status;
  3154. }
  3155. status = STATUS_NO_SUCH_DEVICE;
  3156. //
  3157. // Initiliaze output parameter.
  3158. //
  3159. DepthData->DeviceDepth = 0;
  3160. PpDevNodeLockTree(PPL_SIMPLE_READ);
  3161. //
  3162. // Retrieve the PDO from the device instance string.
  3163. //
  3164. deviceObject = IopDeviceObjectFromDeviceInstance(&instance);
  3165. PiControlFreeUserModeCallersBuffer(CallerMode, instance.Buffer);
  3166. if (deviceObject) {
  3167. //
  3168. // Retrieve the devnode from the PDO
  3169. //
  3170. deviceNode = (PDEVICE_NODE)deviceObject->DeviceObjectExtension->DeviceNode;
  3171. if (deviceNode) {
  3172. DepthData->DeviceDepth = deviceNode->Level;
  3173. status = STATUS_SUCCESS;
  3174. }
  3175. ObDereferenceObject(deviceObject);
  3176. }
  3177. PpDevNodeUnlockTree(PPL_SIMPLE_READ);
  3178. return status;
  3179. }
  3180. NTSTATUS
  3181. PiControlQueryDeviceRelations(
  3182. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  3183. IN OUT PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA RelationsData,
  3184. IN ULONG PnPControlDataLength,
  3185. IN KPROCESSOR_MODE CallerMode
  3186. )
  3187. /*++
  3188. Routine Description:
  3189. This routine is invoked to query and return the device relations of a
  3190. particular devnode.
  3191. Arguments:
  3192. PnPControlClass - Should be PlugPlayControlQueryDeviceRelations.
  3193. RelationsData - Points to buffer that receives the depth.
  3194. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA)
  3195. CallerMode - Processor mode of caller (UserMode/KernelMode)
  3196. Return Value:
  3197. NTSTATUS code (note: must be convertible to user-mode Win32 error)
  3198. --*/
  3199. {
  3200. NTSTATUS status, tempStatus;
  3201. UNICODE_STRING instance;
  3202. ULONG length;
  3203. PVOID buffer;
  3204. PAGED_CODE();
  3205. UNREFERENCED_PARAMETER (PnPControlClass);
  3206. UNREFERENCED_PARAMETER (PnPControlDataLength);
  3207. ASSERT(PnPControlClass == PlugPlayControlQueryDeviceRelations);
  3208. ASSERT(PnPControlDataLength == sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA));
  3209. //
  3210. // Validate device instance.
  3211. //
  3212. instance.Length = instance.MaximumLength = RelationsData->DeviceInstance.Length;
  3213. if ( instance.Length == 0 ||
  3214. instance.Length > CWC_TO_CB(MAX_DEVICE_ID_LEN) ||
  3215. (instance.Length & 1)) {
  3216. return STATUS_INVALID_PARAMETER;
  3217. }
  3218. buffer = NULL;
  3219. instance.Buffer = NULL;
  3220. if (RelationsData->BufferLength && RelationsData->Buffer) {
  3221. length = RelationsData->BufferLength * sizeof(WCHAR);
  3222. } else {
  3223. length = 0;
  3224. }
  3225. status = PiControlAllocateBufferForUserModeCaller(
  3226. &buffer,
  3227. length,
  3228. CallerMode,
  3229. RelationsData->Buffer);
  3230. if (!NT_SUCCESS(status)) {
  3231. goto Clean0;
  3232. }
  3233. status = PiControlMakeUserModeCallersCopy(
  3234. &instance.Buffer,
  3235. RelationsData->DeviceInstance.Buffer,
  3236. instance.Length,
  3237. sizeof(WCHAR),
  3238. CallerMode,
  3239. TRUE);
  3240. if (!NT_SUCCESS(status)) {
  3241. goto Clean0;
  3242. }
  3243. status = PiQueryDeviceRelations(&instance,
  3244. RelationsData->Operation,
  3245. &length,
  3246. buffer);
  3247. if (buffer) {
  3248. tempStatus = PiControlMakeUserModeCallersCopy(
  3249. &RelationsData->Buffer,
  3250. buffer,
  3251. RelationsData->BufferLength * sizeof(WCHAR),
  3252. sizeof(WCHAR),
  3253. CallerMode,
  3254. FALSE);
  3255. if (!NT_SUCCESS(tempStatus)) {
  3256. status = tempStatus;
  3257. }
  3258. }
  3259. RelationsData->BufferLength = length / sizeof(WCHAR);
  3260. Clean0:
  3261. PiControlFreeUserModeCallersBuffer(CallerMode, buffer);
  3262. PiControlFreeUserModeCallersBuffer(CallerMode, instance.Buffer);
  3263. return status;
  3264. }
  3265. NTSTATUS
  3266. PiControlQueryTargetDeviceRelation(
  3267. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  3268. IN OUT PPLUGPLAY_CONTROL_TARGET_RELATION_DATA TargetData,
  3269. IN ULONG PnPControlDataLength,
  3270. IN KPROCESSOR_MODE CallerMode
  3271. )
  3272. /*++
  3273. Routine Description:
  3274. This routine is invoked to query and return the target device relations of a
  3275. particular devnode.
  3276. Arguments:
  3277. PnPControlClass - Should be PlugPlayControlTargetDeviceRelation.
  3278. TargetData - Points to buffer that receives the depth.
  3279. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_TARGET_RELATION_DATA)
  3280. CallerMode - Processor mode of caller (UserMode/KernelMode)
  3281. Return Value:
  3282. NTSTATUS code (note: must be convertible to user-mode Win32 error)
  3283. --*/
  3284. {
  3285. NTSTATUS status;
  3286. PFILE_OBJECT fileObject;
  3287. PDEVICE_NODE deviceNode;
  3288. ULONG requiredLength;
  3289. PAGED_CODE();
  3290. UNREFERENCED_PARAMETER (PnPControlClass);
  3291. UNREFERENCED_PARAMETER (PnPControlDataLength);
  3292. ASSERT(PnPControlClass == PlugPlayControlTargetDeviceRelation);
  3293. ASSERT(PnPControlDataLength == sizeof(PLUGPLAY_CONTROL_TARGET_RELATION_DATA));
  3294. //
  3295. // Retrieve the file object for the specified file handle.
  3296. //
  3297. status = ObReferenceObjectByHandle(
  3298. TargetData->UserFileHandle,
  3299. FILE_ANY_ACCESS,
  3300. IoFileObjectType,
  3301. CallerMode,
  3302. (PVOID *)&fileObject,
  3303. NULL);
  3304. if (!NT_SUCCESS(status)) {
  3305. return status;
  3306. }
  3307. deviceNode = NULL;
  3308. TargetData->DeviceInstanceLen *= sizeof(WCHAR);
  3309. //
  3310. // Now retrieve the actual target device object associate with this
  3311. // file object.
  3312. //
  3313. status = IopGetRelatedTargetDevice(fileObject, &deviceNode);
  3314. if (!NT_SUCCESS(status)) {
  3315. goto Clean;
  3316. }
  3317. ASSERT(deviceNode);
  3318. requiredLength = deviceNode->InstancePath.Length + sizeof(UNICODE_NULL);
  3319. if (TargetData->DeviceInstanceLen < requiredLength) {
  3320. status = STATUS_BUFFER_TOO_SMALL;
  3321. TargetData->DeviceInstanceLen = requiredLength;
  3322. goto Clean;
  3323. }
  3324. TargetData->DeviceInstanceLen = requiredLength;
  3325. status = PiControlCopyUserModeCallersBuffer(
  3326. TargetData->DeviceInstance,
  3327. deviceNode->InstancePath.Buffer,
  3328. requiredLength,
  3329. sizeof(WCHAR),
  3330. CallerMode,
  3331. FALSE);
  3332. Clean:
  3333. TargetData->DeviceInstanceLen /= sizeof(WCHAR);
  3334. if (deviceNode) {
  3335. //
  3336. // Drop the reference placed by IopGetRelatedTargetDevice.
  3337. //
  3338. ObDereferenceObject(deviceNode->PhysicalDeviceObject);
  3339. }
  3340. ObDereferenceObject(fileObject);
  3341. return status;
  3342. }
  3343. NTSTATUS
  3344. PiControlQueryConflictList(
  3345. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  3346. IN OUT PPLUGPLAY_CONTROL_CONFLICT_DATA ConflictData,
  3347. IN ULONG PnPControlDataLength,
  3348. IN KPROCESSOR_MODE CallerMode
  3349. )
  3350. /*++
  3351. Routine Description:
  3352. This routine retrieves device conflict data.
  3353. NOTE: This routine surpasses PiDetectResourceConflict in functionality
  3354. Arguments:
  3355. PnPControlClass - Should be PlugPlayControlQueryConflictList
  3356. ConflictData - Points to buffer that receives conflict data.
  3357. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_CONFLICT_DATA)
  3358. CallerMode - Processor mode of caller (UserMode/KernelMode)
  3359. Return Value:
  3360. NTSTATUS code (note: must be convertible to user-mode Win32 error)
  3361. --*/
  3362. {
  3363. NTSTATUS status, tempStatus;
  3364. PDEVICE_OBJECT deviceObject;
  3365. PDEVICE_NODE deviceNode;
  3366. PVOID list, buffer;
  3367. UNICODE_STRING instance;
  3368. PAGED_CODE();
  3369. UNREFERENCED_PARAMETER (PnPControlClass);
  3370. UNREFERENCED_PARAMETER (PnPControlDataLength);
  3371. ASSERT(PnPControlClass == PlugPlayControlQueryConflictList);
  3372. ASSERT(PnPControlDataLength == sizeof(PLUGPLAY_CONTROL_CONFLICT_DATA));
  3373. //
  3374. // Sanity check the conflict list size.
  3375. //
  3376. if ( ConflictData->ConflictBuffer == NULL ||
  3377. ConflictData->ConflictBufferSize < MIN_CONFLICT_LIST_SIZE) {
  3378. return STATUS_BUFFER_TOO_SMALL;
  3379. }
  3380. //
  3381. // Make sure the resource list has one and only one descriptor.
  3382. //
  3383. if ( ConflictData->ResourceList == NULL ||
  3384. ConflictData->ResourceListSize < sizeof(CM_RESOURCE_LIST) ||
  3385. ConflictData->ResourceList->Count != 1 ||
  3386. ConflictData->ResourceList->List[0].PartialResourceList.Count != 1) {
  3387. return STATUS_INVALID_PARAMETER;
  3388. }
  3389. //
  3390. // Validate instance path.
  3391. //
  3392. instance.Length = instance.MaximumLength = ConflictData->DeviceInstance.Length;
  3393. if ( instance.Length == 0 ||
  3394. instance.Length > CWC_TO_CB(MAX_DEVICE_ID_LEN) ||
  3395. (instance.Length & 1)) {
  3396. return STATUS_INVALID_PARAMETER;
  3397. }
  3398. list = NULL;
  3399. buffer = NULL;
  3400. deviceObject = NULL;
  3401. instance.Buffer = NULL;
  3402. status = PiControlMakeUserModeCallersCopy(
  3403. &list,
  3404. ConflictData->ResourceList,
  3405. ConflictData->ResourceListSize,
  3406. sizeof(UCHAR),
  3407. CallerMode,
  3408. TRUE);
  3409. if (!NT_SUCCESS(status)) {
  3410. goto Clean0;
  3411. }
  3412. status = PiControlAllocateBufferForUserModeCaller(
  3413. &buffer,
  3414. ConflictData->ConflictBufferSize,
  3415. CallerMode,
  3416. ConflictData->ConflictBuffer);
  3417. if (!NT_SUCCESS(status)) {
  3418. goto Clean0;
  3419. }
  3420. status = PiControlMakeUserModeCallersCopy(
  3421. &instance.Buffer,
  3422. ConflictData->DeviceInstance.Buffer,
  3423. ConflictData->DeviceInstance.Length,
  3424. sizeof(WCHAR),
  3425. CallerMode,
  3426. TRUE);
  3427. if (!NT_SUCCESS(status)) {
  3428. goto Clean0;
  3429. }
  3430. //
  3431. // Preinit for failure
  3432. //
  3433. status = STATUS_NO_SUCH_DEVICE;
  3434. //
  3435. // We don't do simple reads because we want to ensure we don't send this
  3436. // while a remove is in progress...
  3437. //
  3438. PpDevNodeLockTree(PPL_TREEOP_ALLOW_READS);
  3439. //
  3440. // Retrieve the PDO from the device instance string.
  3441. //
  3442. deviceObject = IopDeviceObjectFromDeviceInstance(&instance);
  3443. if (deviceObject) {
  3444. //
  3445. // Retrieve the devnode from the PDO
  3446. //
  3447. deviceNode = (PDEVICE_NODE)deviceObject->DeviceObjectExtension->DeviceNode;
  3448. //
  3449. // We don't want to bother with things not in the tree, and we want to
  3450. // skip the root.
  3451. //
  3452. if ( deviceNode && deviceNode != IopRootDeviceNode &&
  3453. deviceNode->State != DeviceNodeDeletePendingCloses &&
  3454. deviceNode->State != DeviceNodeDeleted) {
  3455. //
  3456. // parameters validated
  3457. //
  3458. status = IopQueryConflictList(
  3459. deviceObject,
  3460. list,
  3461. ConflictData->ResourceListSize,
  3462. buffer,
  3463. ConflictData->ConflictBufferSize,
  3464. ConflictData->Flags);
  3465. tempStatus = PiControlMakeUserModeCallersCopy(
  3466. &ConflictData->ConflictBuffer,
  3467. buffer,
  3468. ConflictData->ConflictBufferSize,
  3469. sizeof(UCHAR),
  3470. CallerMode,
  3471. FALSE);
  3472. if (!NT_SUCCESS(tempStatus)) {
  3473. status = tempStatus;
  3474. }
  3475. }
  3476. }
  3477. PpDevNodeUnlockTree(PPL_TREEOP_ALLOW_READS);
  3478. Clean0:
  3479. PiControlFreeUserModeCallersBuffer(CallerMode, list);
  3480. PiControlFreeUserModeCallersBuffer(CallerMode, buffer);
  3481. PiControlFreeUserModeCallersBuffer(CallerMode, instance.Buffer);
  3482. if (deviceObject) {
  3483. ObDereferenceObject(deviceObject);
  3484. }
  3485. ConflictData->Status = status;
  3486. return status;
  3487. }
  3488. NTSTATUS
  3489. PiControlRetrieveDockData(
  3490. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  3491. IN OUT PPLUGPLAY_CONTROL_RETRIEVE_DOCK_DATA DockData,
  3492. IN ULONG PnPControlDataLength,
  3493. IN KPROCESSOR_MODE CallerMode
  3494. )
  3495. /*++
  3496. Routine Description:
  3497. This routine retrieves dock data.
  3498. Arguments:
  3499. PnPControlClass - Should be PlugPlayControlRetrieveDock
  3500. ConflictData - Points to buffer that receives conflict data.
  3501. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_RETRIEVE_DOCK_DATA)
  3502. CallerMode - Processor mode of caller (UserMode/KernelMode)
  3503. Return Value:
  3504. NTSTATUS code (note: must be convertible to user-mode Win32 error)
  3505. --*/
  3506. {
  3507. NTSTATUS status;
  3508. PDEVICE_OBJECT dockDevice;
  3509. PDEVICE_NODE deviceNode;
  3510. ULONG requiredSize;
  3511. PAGED_CODE();
  3512. UNREFERENCED_PARAMETER (PnPControlClass);
  3513. UNREFERENCED_PARAMETER (PnPControlDataLength);
  3514. ASSERT(PnPControlClass == PlugPlayControlRetrieveDock);
  3515. ASSERT(PnPControlDataLength == sizeof(PLUGPLAY_CONTROL_RETRIEVE_DOCK_DATA));
  3516. requiredSize = DockData->DeviceInstanceLength * sizeof(WCHAR);
  3517. dockDevice = PpProfileRetrievePreferredDockToEject();
  3518. if (dockDevice == NULL) {
  3519. status = STATUS_NO_SUCH_DEVICE;
  3520. goto Clean0;
  3521. }
  3522. deviceNode = (PDEVICE_NODE)dockDevice->DeviceObjectExtension->DeviceNode;
  3523. if (deviceNode == NULL) {
  3524. ASSERT(deviceNode);
  3525. status = STATUS_NO_SUCH_DEVICE;
  3526. goto Clean0;
  3527. }
  3528. requiredSize = deviceNode->InstancePath.Length + sizeof(UNICODE_NULL);
  3529. if (DockData->DeviceInstanceLength < requiredSize) {
  3530. status = STATUS_BUFFER_TOO_SMALL;
  3531. goto Clean0;
  3532. }
  3533. status = PiControlCopyUserModeCallersBuffer(
  3534. DockData->DeviceInstance,
  3535. deviceNode->InstancePath.Buffer,
  3536. requiredSize,
  3537. sizeof(WCHAR),
  3538. CallerMode,
  3539. FALSE);
  3540. Clean0:
  3541. DockData->DeviceInstanceLength = requiredSize / sizeof(WCHAR);
  3542. if (dockDevice) {
  3543. ObDereferenceObject(dockDevice);
  3544. }
  3545. return status;
  3546. }
  3547. NTSTATUS
  3548. PiControlGetDevicePowerData(
  3549. IN PDEVICE_NODE DeviceNode,
  3550. IN KPROCESSOR_MODE CallerMode,
  3551. IN ULONG OutputBufferLength,
  3552. IN PVOID PowerDataBuffer OPTIONAL,
  3553. OUT ULONG *BytesWritten
  3554. )
  3555. /*++
  3556. Routine Description:
  3557. This routine retrieves power information for a given devnode.
  3558. Arguments:
  3559. DeviceNode - The device node to retrieve CM_POWER_DATA for.
  3560. CallerMode - Processor mode of caller (UserMode/KernelMode)
  3561. OutputBufferLength - Size of the output buffer.
  3562. PowerDataBuffer - Points to buffer that receives the power data.
  3563. BytesWritten - Receives the number of bytes written into the buffer.
  3564. Return Value:
  3565. NTSTATUS code (note: must be convertible to user-mode Win32 error)
  3566. If the status is STATUS_BUFFER_OVERFLOW, BytesWritten isn't
  3567. filled with OutputBufferLength, but rather the full size of
  3568. the requested structure.
  3569. --*/
  3570. {
  3571. NTSTATUS status;
  3572. DEVICE_CAPABILITIES deviceCapabilities;
  3573. DEVICE_POWER_STATE dState, deepestDeviceWakeState;
  3574. SYSTEM_POWER_STATE sState;
  3575. ULONG i;
  3576. CM_POWER_DATA cmPowerData;
  3577. UNREFERENCED_PARAMETER (CallerMode);
  3578. //
  3579. // The structure size serves as a versioning mechanism. Since we only have
  3580. // one version of the data today, we don't have to test OutputBufferLength.
  3581. //
  3582. cmPowerData.PD_Size = sizeof(CM_POWER_DATA);
  3583. *BytesWritten = 0;
  3584. if (OutputBufferLength < sizeof(ULONG)) {
  3585. //
  3586. // Assume the *minimum* structure size.
  3587. //
  3588. *BytesWritten = cmPowerData.PD_Size;
  3589. return STATUS_BUFFER_OVERFLOW;
  3590. }
  3591. status = PpIrpQueryCapabilities(DeviceNode->PhysicalDeviceObject, &deviceCapabilities);
  3592. if (!NT_SUCCESS(status)) {
  3593. return STATUS_NO_SUCH_DEVICE;
  3594. }
  3595. //
  3596. // Fill out the "current" power state. Nonstarted devices are said to be
  3597. // in D3.
  3598. //
  3599. if (PipIsDevNodeDNStarted(DeviceNode)) {
  3600. PoGetDevicePowerState(
  3601. DeviceNode->PhysicalDeviceObject,
  3602. &cmPowerData.PD_MostRecentPowerState
  3603. );
  3604. } else {
  3605. cmPowerData.PD_MostRecentPowerState = PowerDeviceD3;
  3606. }
  3607. //
  3608. // Fill out the power data.
  3609. //
  3610. cmPowerData.PD_Capabilities = PDCAP_D0_SUPPORTED | PDCAP_D3_SUPPORTED;
  3611. if (deviceCapabilities.DeviceD1) {
  3612. cmPowerData.PD_Capabilities |= PDCAP_D1_SUPPORTED;
  3613. }
  3614. if (deviceCapabilities.DeviceD2) {
  3615. cmPowerData.PD_Capabilities |= PDCAP_D2_SUPPORTED;
  3616. }
  3617. if (deviceCapabilities.WakeFromD0) {
  3618. cmPowerData.PD_Capabilities |= PDCAP_WAKE_FROM_D0_SUPPORTED;
  3619. }
  3620. if (deviceCapabilities.WakeFromD1) {
  3621. cmPowerData.PD_Capabilities |= PDCAP_WAKE_FROM_D1_SUPPORTED;
  3622. }
  3623. if (deviceCapabilities.WakeFromD2) {
  3624. cmPowerData.PD_Capabilities |= PDCAP_WAKE_FROM_D2_SUPPORTED;
  3625. }
  3626. if (deviceCapabilities.WakeFromD3) {
  3627. cmPowerData.PD_Capabilities |= PDCAP_WAKE_FROM_D3_SUPPORTED;
  3628. }
  3629. if (deviceCapabilities.WarmEjectSupported) {
  3630. cmPowerData.PD_Capabilities |= PDCAP_WARM_EJECT_SUPPORTED;
  3631. }
  3632. RtlCopyMemory(
  3633. cmPowerData.PD_PowerStateMapping,
  3634. deviceCapabilities.DeviceState,
  3635. sizeof(cmPowerData.PD_PowerStateMapping)
  3636. );
  3637. cmPowerData.PD_D1Latency = deviceCapabilities.D1Latency;
  3638. cmPowerData.PD_D2Latency = deviceCapabilities.D2Latency;
  3639. cmPowerData.PD_D3Latency = deviceCapabilities.D3Latency;
  3640. //
  3641. // First examine DeviceWake, then SystemWake, and update the Wake/D-state
  3642. // bits appropriately. This is for those older WDM 1.0 bus drivers that
  3643. // don't bother to set the DeviceDx and WakeFromDx fields.
  3644. //
  3645. dState = deviceCapabilities.DeviceWake;
  3646. for(i=0; i<2; i++) {
  3647. switch(dState) {
  3648. case PowerDeviceD0:
  3649. cmPowerData.PD_Capabilities |= PDCAP_WAKE_FROM_D0_SUPPORTED;
  3650. break;
  3651. case PowerDeviceD1:
  3652. cmPowerData.PD_Capabilities |= ( PDCAP_D1_SUPPORTED |
  3653. PDCAP_WAKE_FROM_D1_SUPPORTED );
  3654. break;
  3655. case PowerDeviceD2:
  3656. cmPowerData.PD_Capabilities |= ( PDCAP_D2_SUPPORTED |
  3657. PDCAP_WAKE_FROM_D2_SUPPORTED );
  3658. break;
  3659. case PowerDeviceD3:
  3660. cmPowerData.PD_Capabilities |= PDCAP_WAKE_FROM_D3_SUPPORTED;
  3661. break;
  3662. default:
  3663. ASSERT(0);
  3664. case PowerDeviceUnspecified:
  3665. break;
  3666. }
  3667. if (deviceCapabilities.SystemWake != PowerSystemUnspecified) {
  3668. dState = deviceCapabilities.DeviceState[deviceCapabilities.SystemWake];
  3669. } else {
  3670. dState = PowerDeviceUnspecified;
  3671. }
  3672. }
  3673. //
  3674. // Calculate the deepest D state for wake
  3675. //
  3676. if (cmPowerData.PD_Capabilities & PDCAP_WAKE_FROM_D3_SUPPORTED) {
  3677. deepestDeviceWakeState = PowerDeviceD3;
  3678. } else if (cmPowerData.PD_Capabilities & PDCAP_WAKE_FROM_D2_SUPPORTED) {
  3679. deepestDeviceWakeState = PowerDeviceD2;
  3680. } else if (cmPowerData.PD_Capabilities & PDCAP_WAKE_FROM_D1_SUPPORTED) {
  3681. deepestDeviceWakeState = PowerDeviceD1;
  3682. } else if (cmPowerData.PD_Capabilities & PDCAP_WAKE_FROM_D0_SUPPORTED) {
  3683. deepestDeviceWakeState = PowerDeviceD0;
  3684. } else {
  3685. deepestDeviceWakeState = PowerDeviceUnspecified;
  3686. }
  3687. //
  3688. // Now fill in the SystemWake field. If this field is unspecified, then we
  3689. // should infer it from the D-state information.
  3690. //
  3691. sState = deviceCapabilities.SystemWake;
  3692. if (sState != PowerSystemUnspecified) {
  3693. //
  3694. // The D-state for SystemWake should provide enough power to cover
  3695. // the deepest device wake state we've found. The only reason this field
  3696. // exists is:
  3697. // 1) Some systems can handle WakeFromS4/S5, while most can't.
  3698. // 2) Some systems use the S state as a proxy for describing
  3699. // D3Hot/D3Cold dependancies.
  3700. //
  3701. ASSERT(deviceCapabilities.DeviceState[sState] <= deepestDeviceWakeState);
  3702. } else if (deepestDeviceWakeState != PowerDeviceUnspecified) {
  3703. //
  3704. // A system wake state wasn't specified, examine each S state and pick
  3705. // the first one that supplies enough power to wake the system. Note
  3706. // that we start with S3. If a driver doesn't set the SystemWake field
  3707. // but can wake the system from D3, we do *not* assume the driver can
  3708. // wake the system from S4 or S5.
  3709. //
  3710. for(sState=PowerSystemSleeping3; sState>=PowerSystemWorking; sState--) {
  3711. if ((deviceCapabilities.DeviceState[i] != PowerDeviceUnspecified) &&
  3712. (deviceCapabilities.DeviceState[i] <= deepestDeviceWakeState)) {
  3713. break;
  3714. }
  3715. }
  3716. //
  3717. // If we didn't find a state, sState is PowerSystemUnspecified.
  3718. //
  3719. }
  3720. cmPowerData.PD_DeepestSystemWake = sState;
  3721. if (OutputBufferLength < cmPowerData.PD_Size) {
  3722. if (ARGUMENT_PRESENT(PowerDataBuffer)) {
  3723. RtlCopyMemory(PowerDataBuffer, &cmPowerData, OutputBufferLength);
  3724. }
  3725. *BytesWritten = cmPowerData.PD_Size;
  3726. status = STATUS_BUFFER_OVERFLOW;
  3727. } else {
  3728. if (ARGUMENT_PRESENT(PowerDataBuffer)) {
  3729. RtlCopyMemory(PowerDataBuffer, &cmPowerData, cmPowerData.PD_Size);
  3730. }
  3731. *BytesWritten = cmPowerData.PD_Size;
  3732. status = STATUS_SUCCESS;
  3733. }
  3734. return status;
  3735. }
  3736. NTSTATUS
  3737. PiControlHaltDevice(
  3738. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  3739. IN OUT PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA DeviceControlData,
  3740. IN ULONG PnPControlDataLength,
  3741. IN KPROCESSOR_MODE CallerMode
  3742. )
  3743. /*++
  3744. Routine Description:
  3745. This routine simulates a surprise remove for a given device.
  3746. Arguments:
  3747. PnPControlClass - Should be PlugPlayControlHaltDevice
  3748. ConflictData - Points to buffer that receives conflict data.
  3749. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)
  3750. CallerMode - Processor mode of caller (UserMode/KernelMode)
  3751. Return Value:
  3752. NTSTATUS code (note: must be convertible to user-mode Win32 error)
  3753. --*/
  3754. {
  3755. NTSTATUS status;
  3756. UNICODE_STRING instance;
  3757. PAGED_CODE();
  3758. UNREFERENCED_PARAMETER (PnPControlClass);
  3759. UNREFERENCED_PARAMETER (PnPControlDataLength);
  3760. instance.Length = instance.MaximumLength = DeviceControlData->DeviceInstance.Length;
  3761. if ( instance.Length == 0 ||
  3762. instance.Length > CWC_TO_CB(MAX_DEVICE_ID_LEN) ||
  3763. (instance.Length & 1)) {
  3764. return STATUS_INVALID_PARAMETER;
  3765. }
  3766. status = PiControlMakeUserModeCallersCopy(
  3767. &instance.Buffer,
  3768. DeviceControlData->DeviceInstance.Buffer,
  3769. DeviceControlData->DeviceInstance.Length,
  3770. sizeof(WCHAR),
  3771. CallerMode,
  3772. TRUE);
  3773. if (NT_SUCCESS(status)) {
  3774. //
  3775. // Queue an event to start the device
  3776. //
  3777. status = PiQueueDeviceRequest(
  3778. &instance,
  3779. HaltDevice,
  3780. DeviceControlData->Flags,
  3781. TRUE);
  3782. PiControlFreeUserModeCallersBuffer(CallerMode, instance.Buffer);
  3783. }
  3784. return status;
  3785. }
  3786. NTSTATUS
  3787. PiControlGetBlockedDriverData(
  3788. IN PLUGPLAY_CONTROL_CLASS PnPControlClass,
  3789. IN OUT PPLUGPLAY_CONTROL_BLOCKED_DRIVER_DATA BlockedDriverData,
  3790. IN ULONG PnPControlDataLength,
  3791. IN KPROCESSOR_MODE CallerMode
  3792. )
  3793. /*++
  3794. Routine Description:
  3795. This routine retrieves the information about drivers blocked from loading
  3796. on this boot.
  3797. Arguments:
  3798. PnPControlClass - Should be PlugPlayControlHaltDevice
  3799. BlockedDriverData - Points to buffer that receives blocked driver data.
  3800. PnPControlDataLength - Should be sizeof(PLUGPLAY_CONTROL_BLOCKED_DRIVER_DATA)
  3801. CallerMode - Processor mode of caller (UserMode/KernelMode)
  3802. Return Value:
  3803. NTSTATUS code (note: must be convertible to user-mode Win32 error)
  3804. --*/
  3805. {
  3806. NTSTATUS status, tempStatus;
  3807. ULONG length;
  3808. PWCHAR buffer;
  3809. PAGED_CODE();
  3810. UNREFERENCED_PARAMETER (PnPControlDataLength);
  3811. UNREFERENCED_PARAMETER (PnPControlClass);
  3812. buffer = NULL;
  3813. if (BlockedDriverData->BufferLength && BlockedDriverData->Buffer) {
  3814. length = BlockedDriverData->BufferLength;
  3815. } else {
  3816. length = 0;
  3817. }
  3818. status = PiControlAllocateBufferForUserModeCaller(
  3819. &buffer,
  3820. length,
  3821. CallerMode,
  3822. BlockedDriverData->Buffer);
  3823. if (!NT_SUCCESS(status)) {
  3824. goto Clean0;
  3825. }
  3826. status = PpGetBlockedDriverList(
  3827. (GUID *)buffer,
  3828. &length,
  3829. BlockedDriverData->Flags);
  3830. if (buffer && NT_SUCCESS(status)) {
  3831. tempStatus = PiControlMakeUserModeCallersCopy(
  3832. &BlockedDriverData->Buffer,
  3833. buffer,
  3834. BlockedDriverData->BufferLength,
  3835. sizeof(ULONG),
  3836. CallerMode,
  3837. FALSE);
  3838. if (!NT_SUCCESS(tempStatus)) {
  3839. status = tempStatus;
  3840. }
  3841. }
  3842. BlockedDriverData->BufferLength = length;
  3843. Clean0:
  3844. //
  3845. // Release any allocated storage.
  3846. //
  3847. PiControlFreeUserModeCallersBuffer(CallerMode, buffer);
  3848. return status;
  3849. }
  3850. #if DBG
  3851. LONG
  3852. PiControlExceptionFilter(
  3853. IN PEXCEPTION_POINTERS ExceptionPointers
  3854. )
  3855. {
  3856. PAGED_CODE();
  3857. IopDbgPrint((IOP_IOAPI_ERROR_LEVEL,
  3858. "PiExceptionFilter: Exception = 0x%08X, Exception Record = 0x%p, Context Record = 0x%p\n",
  3859. ExceptionPointers->ExceptionRecord->ExceptionCode,
  3860. ExceptionPointers->ExceptionRecord,
  3861. ExceptionPointers->ContextRecord));
  3862. DbgBreakPoint();
  3863. return EXCEPTION_EXECUTE_HANDLER;
  3864. }
  3865. #endif
  3866. #ifdef ALLOC_DATA_PRAGMA
  3867. #pragma data_seg()
  3868. #endif