Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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