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.

3085 lines
81 KiB

  1. /*++
  2. Copyright (c) 1995-2001 Microsoft Corporation
  3. Module Name:
  4. rdevnode.c
  5. Abstract:
  6. This module contains the server-side device node APIs.
  7. PNP_CreateDevInst
  8. PNP_DeviceInstanceAction
  9. PNP_GetDeviceStatus
  10. PNP_SetDeviceProblem
  11. PNP_UninstallDevInst
  12. PNP_AddID
  13. PNP_RegisterDriver
  14. PNP_QueryRemove
  15. PNP_DisableDevInst
  16. PNP_RequestDeviceEject
  17. Author:
  18. Paula Tomlinson (paulat) 7-11-1995
  19. Environment:
  20. User-mode only.
  21. Revision History:
  22. 11-July-1995 paulat
  23. Creation and initial implementation.
  24. --*/
  25. //
  26. // includes
  27. //
  28. #include "precomp.h"
  29. #include "umpnpi.h"
  30. #include "umpnpdat.h"
  31. //
  32. // private prototypes
  33. //
  34. CONFIGRET
  35. SetupDevInst(
  36. IN PCWSTR pszDeviceID,
  37. IN ULONG ulFlags
  38. );
  39. CONFIGRET
  40. CreateDefaultDeviceInstance(
  41. IN PCWSTR pszDeviceID,
  42. IN PCWSTR pszParentID,
  43. IN BOOL bPhantom,
  44. IN BOOL bMigrated
  45. );
  46. ULONG
  47. GetCurrentConfigFlag(
  48. IN PCWSTR pDeviceID
  49. );
  50. BOOL
  51. MarkDevicePhantom(
  52. IN HKEY hKey,
  53. IN ULONG ulValue
  54. );
  55. CONFIGRET
  56. GenerateDeviceInstance(
  57. OUT LPWSTR pszFullDeviceID,
  58. IN LPWSTR pszDeviceID,
  59. IN ULONG ulDevId
  60. );
  61. BOOL
  62. IsDeviceRegistered(
  63. IN LPCWSTR pszDeviceID,
  64. IN LPCWSTR pszService
  65. );
  66. BOOL
  67. IsPrivatePhantomFromFirmware(
  68. IN HKEY hKey
  69. );
  70. typedef struct {
  71. LIST_ENTRY ListEntry;
  72. WCHAR DevInst[ANYSIZE_ARRAY];
  73. } ENUM_ELEMENT, *PENUM_ELEMENT;
  74. CONFIGRET
  75. EnumerateSubTreeTopDownBreadthFirstWorker(
  76. IN handle_t BindingHandle,
  77. IN LPCWSTR DevInst,
  78. IN OUT PLIST_ENTRY ListHead
  79. );
  80. //
  81. // global data
  82. //
  83. extern HKEY ghEnumKey; // Key to HKLM\CCC\System\Enum - DO NOT MODIFY
  84. extern HKEY ghServicesKey; // Key to HKLM\CCC\System\Services - DO NOT MODIFY
  85. CONFIGRET
  86. PNP_CreateDevInst(
  87. IN handle_t hBinding,
  88. IN OUT LPWSTR pszDeviceID,
  89. IN LPWSTR pszParentDeviceID,
  90. IN ULONG ulLength,
  91. IN ULONG ulFlags
  92. )
  93. /*++
  94. Routine Description:
  95. This is the RPC server entry point for the CM_Create_DevNode routine.
  96. Arguments:
  97. hBinding RPC binding handle.
  98. pszDeviceID Device instance to create.
  99. pszParentDeviceID Parent of the new device.
  100. ulLength Max length of pDeviceID on input and output.
  101. ulFlags This value depends on the value of the ulMajorAction and
  102. further defines the specific action to perform
  103. Return Value:
  104. If the function succeeds, the return value is CR_SUCCESS. Otherwise it
  105. returns a CR_ error code.
  106. --*/
  107. {
  108. CONFIGRET Status = CR_SUCCESS;
  109. ULONG RegStatus = ERROR_SUCCESS;
  110. HKEY hKey = NULL;
  111. WCHAR szFullDeviceID[MAX_DEVICE_ID_LEN];
  112. ULONG ulStatusFlag=0, ulConfigFlag=0, ulCSConfigFlag=0, ulProblem=0;
  113. ULONG ulPhantom = 0, ulMigrated = 0;
  114. ULONG ulSize=0;
  115. PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
  116. WCHAR szService[MAX_PATH];
  117. NTSTATUS ntStatus;
  118. try {
  119. //
  120. // Verify client privilege
  121. //
  122. if (!VerifyClientAccess(hBinding, &gLuidLoadDriverPrivilege)) {
  123. Status = CR_ACCESS_DENIED;
  124. goto Clean0;
  125. }
  126. //
  127. // validate parameters
  128. //
  129. if (INVALID_FLAGS(ulFlags, CM_CREATE_DEVNODE_BITS)) {
  130. Status = CR_INVALID_FLAG;
  131. goto Clean0;
  132. }
  133. //
  134. // Additionally, Windows NT does not support the
  135. // CM_CREATE_DEVNODE_NO_WAIT_INSTALL flag.
  136. //
  137. if (ulFlags & CM_CREATE_DEVNODE_NO_WAIT_INSTALL) {
  138. Status = CR_INVALID_FLAG;
  139. goto Clean0;
  140. }
  141. //
  142. // RULE: validate that parent is the root devnode; only allow creating
  143. // root enumerating devices using this routine.
  144. //
  145. if (!IsRootDeviceID(pszParentDeviceID)) {
  146. Status = CR_INVALID_DEVINST;
  147. goto Clean0;
  148. }
  149. //
  150. // create a unique instance value if requested
  151. //
  152. if (ulFlags & CM_CREATE_DEVNODE_GENERATE_ID) {
  153. Status = GenerateDeviceInstance(szFullDeviceID,
  154. (LPTSTR)pszDeviceID,
  155. MAX_DEVICE_ID_LEN);
  156. if (Status != CR_SUCCESS) {
  157. goto Clean0;
  158. }
  159. if (((ULONG)lstrlen(szFullDeviceID) + 1) > ulLength) {
  160. Status = CR_BUFFER_SMALL;
  161. goto Clean0;
  162. }
  163. lstrcpy(pszDeviceID, szFullDeviceID);
  164. }
  165. //
  166. // try opening the registry key for this device instance
  167. //
  168. RegStatus = RegOpenKeyEx(ghEnumKey, pszDeviceID, 0,
  169. KEY_READ | KEY_WRITE, &hKey);
  170. KdPrintEx((DPFLTR_PNPMGR_ID,
  171. DBGF_REGISTRY,
  172. "UMPNPMGR: PNP_CreateDevInst opened key %ws\n",
  173. pszDeviceID));
  174. //
  175. // if the key already exists, check if it is marked as "Migrated".
  176. //
  177. if (RegStatus == ERROR_SUCCESS) {
  178. ulSize = sizeof(ULONG);
  179. if (RegQueryValueEx(hKey,
  180. pszRegValueMigrated,
  181. NULL,
  182. NULL,
  183. (LPBYTE)&ulMigrated,
  184. &ulSize) != ERROR_SUCCESS) {
  185. ulMigrated = 0;
  186. } else {
  187. //
  188. // if the value exists at all, be paranoid and check that it's 1
  189. //
  190. ASSERT(ulMigrated == 1);
  191. }
  192. }
  193. //
  194. // first handle phantom devnode case
  195. //
  196. if (ulFlags & CM_CREATE_DEVNODE_PHANTOM) {
  197. //
  198. // for a phantom devnode, it must not already exist in the registry
  199. // unless it's an unregistered firmware mapper device instance.
  200. //
  201. if (RegStatus == ERROR_SUCCESS) {
  202. ASSERT(hKey != NULL);
  203. //
  204. // Check to see if the device is migrated, or is a firmware
  205. // mapper-created phantom--if so, it's OK to allow the create to
  206. // succeed.
  207. //
  208. if (ulMigrated != 0) {
  209. //
  210. // this key was specifically request (not generated) so it
  211. // will be used -- remove the migrated value.
  212. //
  213. RegDeleteValue(hKey, pszRegValueMigrated);
  214. Status = CR_SUCCESS;
  215. } else if (IsPrivatePhantomFromFirmware(hKey)) {
  216. Status = CR_SUCCESS;
  217. } else {
  218. Status = CR_ALREADY_SUCH_DEVINST;
  219. }
  220. goto Clean0;
  221. }
  222. //
  223. // it doesn't exist in the registry so create a phantom devnode
  224. //
  225. CreateDefaultDeviceInstance(pszDeviceID,
  226. pszParentDeviceID,
  227. TRUE,
  228. FALSE);
  229. goto Clean0;
  230. }
  231. //
  232. // for a normal devnode, fail if the device is already present in the
  233. // registry and alive, and not migrated
  234. //
  235. if ((RegStatus == ERROR_SUCCESS) &&
  236. (IsDeviceIdPresent(pszDeviceID)) &&
  237. (ulMigrated == 0)) {
  238. //
  239. // Set status to NEEDS ENUM and fail the create call.
  240. //
  241. Status = CR_ALREADY_SUCH_DEVINST;
  242. goto Clean0;
  243. }
  244. //
  245. // if couldn't open the device instance, or the key was migrated, then
  246. // most likely the key doesn't exist yet, or should be treated as if it
  247. // doesn't exist yet, so create a device instance key with default
  248. // values.
  249. //
  250. if ((RegStatus != ERROR_SUCCESS) || (ulMigrated != 0)) {
  251. //
  252. // this key will be used -- remove the migrated value
  253. // and close the key.
  254. //
  255. if (ulMigrated != 0) {
  256. ASSERT(RegStatus == ERROR_SUCCESS);
  257. ASSERT(hKey != NULL);
  258. RegDeleteValue(hKey, pszRegValueMigrated);
  259. RegCloseKey(hKey);
  260. hKey = NULL;
  261. }
  262. //
  263. // create the default device instance, finding and unused instance
  264. // if necessary. if the key was migrated, a new key will not be
  265. // created, but the default instance data will be added to the
  266. // existing key.
  267. //
  268. CreateDefaultDeviceInstance(pszDeviceID,
  269. pszParentDeviceID,
  270. FALSE,
  271. (ulMigrated != 0));
  272. KdPrintEx((DPFLTR_PNPMGR_ID,
  273. DBGF_REGISTRY,
  274. "UMPNPMGR: PNP_CreateDevInst opened key %ws\n",
  275. pszDeviceID));
  276. RegStatus = RegOpenKeyEx(ghEnumKey, pszDeviceID, 0,
  277. KEY_READ | KEY_WRITE, &hKey);
  278. if (RegStatus != ERROR_SUCCESS) {
  279. Status = CR_REGISTRY_ERROR;
  280. goto Clean0;
  281. }
  282. }
  283. //
  284. // retrieve flags
  285. //
  286. ulConfigFlag = GetDeviceConfigFlags(pszDeviceID, hKey);
  287. ulCSConfigFlag = GetCurrentConfigFlag(pszDeviceID);
  288. //
  289. // check if the device is blocked
  290. //
  291. if ((ulCSConfigFlag & CSCONFIGFLAG_DO_NOT_CREATE) ||
  292. (ulConfigFlag & CONFIGFLAG_REMOVED) ||
  293. (ulConfigFlag & CONFIGFLAG_NET_BOOT)) {
  294. Status = CR_CREATE_BLOCKED;
  295. goto Clean0;
  296. }
  297. //
  298. // Call kernel-mode to create the device node
  299. //
  300. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA));
  301. RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceID);
  302. ControlData.Flags = 0;
  303. ntStatus = NtPlugPlayControl(PlugPlayControlInitializeDevice,
  304. &ControlData,
  305. sizeof(ControlData));
  306. if (!NT_SUCCESS(ntStatus)) {
  307. Status = CR_FAILURE;
  308. goto Clean0;
  309. }
  310. //
  311. // Retrieve devnode status
  312. //
  313. GetDeviceStatus(pszDeviceID, &ulStatusFlag, &ulProblem);
  314. //
  315. // Are we converting a phantom into a real devnode?
  316. //
  317. ulSize = sizeof(ULONG);
  318. if (RegQueryValueEx(hKey, pszRegValuePhantom, NULL, NULL,
  319. (LPBYTE)&ulPhantom, &ulSize) != ERROR_SUCCESS) {
  320. ulPhantom = 0;
  321. }
  322. if (ulPhantom) {
  323. //
  324. // If we're turning a phantom into a real devnode, suppress the found new
  325. // hardware popup for this device, then clear the phantom flag.
  326. //
  327. RegDeleteValue(hKey, pszRegValuePhantom);
  328. } else {
  329. //
  330. // if device not installed, set a problem
  331. //
  332. if (ulConfigFlag & CONFIGFLAG_REINSTALL ||
  333. ulConfigFlag & CONFIGFLAG_FAILEDINSTALL) {
  334. SetDeviceStatus(pszDeviceID, DN_HAS_PROBLEM, CM_PROB_NOT_CONFIGURED);
  335. }
  336. }
  337. if (ulFlags & CM_CREATE_DEVNODE_DO_NOT_INSTALL) {
  338. //
  339. // If the device has a service, register it
  340. //
  341. ulSize = MAX_PATH * sizeof(WCHAR);
  342. if (RegQueryValueEx(hKey, pszRegValueService, NULL, NULL,
  343. (LPBYTE)szService, &ulSize) == ERROR_SUCCESS) {
  344. if (szService[0]) {
  345. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA));
  346. RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceID);
  347. ControlData.Flags = 0;
  348. NtPlugPlayControl(PlugPlayControlRegisterNewDevice,
  349. &ControlData,
  350. sizeof(ControlData));
  351. }
  352. }
  353. }
  354. Clean0:
  355. NOTHING;
  356. } except(EXCEPTION_EXECUTE_HANDLER) {
  357. Status = CR_FAILURE;
  358. }
  359. if (hKey != NULL) {
  360. RegCloseKey(hKey);
  361. }
  362. return Status;
  363. } // PNP_CreateDevInst
  364. CONFIGRET
  365. PNP_DeviceInstanceAction(
  366. IN handle_t hBinding,
  367. IN ULONG ulAction,
  368. IN ULONG ulFlags,
  369. IN PCWSTR pszDeviceInstance1,
  370. IN PCWSTR pszDeviceInstance2
  371. )
  372. /*++
  373. Routine Description:
  374. This is the RPC server entry point for the ConfigManager routines that
  375. perform some operation on DevNodes (such as create, setup, disable,
  376. and enable, etc). It handles various routines in this one routine by
  377. accepting a major and minor action value.
  378. Arguments:
  379. hBinding RPC binding handle.
  380. ulMajorAction Specifies the requested action to perform (one of the
  381. PNP_DEVINST_* values)
  382. ulFlags This value depends on the value of the ulMajorAction and
  383. further defines the specific action to perform
  384. pszDeviceInstance1 This is a device instance string to be used in
  385. performing the specified action, it's value depends on
  386. the ulMajorAction value.
  387. pszDeviceInstance2 This is a device instance string to be used in
  388. performing the specified action, it's value depends on
  389. the ulMajorAction value.
  390. Return Value:
  391. If the function succeeds, the return value is CR_SUCCESS.
  392. If the function fails, the return value is one of the following:
  393. CR_ALREADY_SUCH_DEVNODE,
  394. CR_INVALID_DEVICE_ID,
  395. CR_INVALID_DEVNODE,
  396. CR_INVALID_FLAG,
  397. CR_FAILURE,
  398. CR_NOT_DISABLEABLE,
  399. CR_INVALID_POINTER, or
  400. CR_OUT_OF_MEMORY.
  401. --*/
  402. {
  403. CONFIGRET Status = CR_SUCCESS;
  404. try {
  405. //
  406. // Verify client privilege
  407. //
  408. if (!VerifyClientAccess(hBinding, &gLuidLoadDriverPrivilege)) {
  409. return CR_ACCESS_DENIED;
  410. }
  411. PNP_ENTER_SYNCHRONOUS_CALL();
  412. //
  413. // pass the request on to a private routine that handles each major
  414. // device instance action request
  415. //
  416. switch (ulAction) {
  417. case PNP_DEVINST_SETUP:
  418. KdPrintEx((DPFLTR_PNPMGR_ID,
  419. DBGF_INSTALL,
  420. "CM_Setup_DevInst called\n"));
  421. if (IsLegalDeviceId(pszDeviceInstance1)) {
  422. Status = SetupDevInst(pszDeviceInstance1, ulFlags);
  423. } else {
  424. Status = CR_INVALID_DEVNODE;
  425. }
  426. break;
  427. case PNP_DEVINST_ENABLE:
  428. if (IsLegalDeviceId(pszDeviceInstance1)) {
  429. Status = EnableDevInst(pszDeviceInstance1);
  430. } else {
  431. Status = CR_INVALID_DEVNODE;
  432. }
  433. break;
  434. case PNP_DEVINST_REENUMERATE:
  435. KdPrintEx((DPFLTR_PNPMGR_ID,
  436. DBGF_INSTALL,
  437. "CM_Reenumerate_DevInst called\n"));
  438. if (IsLegalDeviceId(pszDeviceInstance1)) {
  439. Status = ReenumerateDevInst(pszDeviceInstance1, TRUE, ulFlags);
  440. } else {
  441. Status = CR_INVALID_DEVNODE;
  442. }
  443. break;
  444. case PNP_DEVINST_DISABLE:
  445. KdPrintEx((DPFLTR_PNPMGR_ID,
  446. DBGF_INSTALL,
  447. "CM_Disable_DevNode called\n"));
  448. Status = CR_CALL_NOT_IMPLEMENTED;
  449. break;
  450. case PNP_DEVINST_QUERYREMOVE:
  451. KdPrintEx((DPFLTR_PNPMGR_ID,
  452. DBGF_INSTALL,
  453. "CM_Query_Remove_SubTree called\n"));
  454. Status = CR_CALL_NOT_IMPLEMENTED;
  455. break;
  456. case PNP_DEVINST_REMOVESUBTREE:
  457. KdPrintEx((DPFLTR_PNPMGR_ID,
  458. DBGF_INSTALL,
  459. "CM_Remove_SubTree called\n"));
  460. Status = CR_CALL_NOT_IMPLEMENTED;
  461. break;
  462. case PNP_DEVINST_REQUEST_EJECT:
  463. KdPrintEx((DPFLTR_PNPMGR_ID,
  464. DBGF_INSTALL,
  465. "CM_Request_Device_Eject called\n"));
  466. Status = CR_CALL_NOT_IMPLEMENTED;
  467. break;
  468. case PNP_DEVINST_MOVE:
  469. Status = CR_CALL_NOT_IMPLEMENTED;
  470. break;
  471. default:
  472. Status = CR_INVALID_FLAG;
  473. break;
  474. }
  475. } except(EXCEPTION_EXECUTE_HANDLER) {
  476. Status = CR_FAILURE;
  477. }
  478. PNP_LEAVE_SYNCHRONOUS_CALL();
  479. return Status;
  480. } // PNP_DeviceInstanceAction
  481. CONFIGRET
  482. PNP_GetDeviceStatus(
  483. IN handle_t hBinding,
  484. IN LPCWSTR pDeviceID,
  485. OUT PULONG pulStatus,
  486. OUT PULONG pulProblem,
  487. IN ULONG ulFlags
  488. )
  489. /*++
  490. Routine Description:
  491. This is the RPC server entry point for the ConfigManager
  492. CM_Get_DevNode_Status routines. It retrieves device instance specific
  493. status information.
  494. Arguments:
  495. hBinding RPC binding handle, not used.
  496. pDeviceID This is a device instance string to retrieve status
  497. information for.
  498. pulStatus Pointer to ULONG variable to return Status Flags in
  499. pulProblem Pointer to ULONG variable to return Problem in
  500. ulFlags Not used, must be zero.
  501. Return Value:
  502. If the function succeeds, the return value is CR_SUCCESS.
  503. If the function fails, the return value is one of the following:
  504. CR_INVALID_DEVNODE,
  505. CR_INVALID_FLAG, or
  506. CR_INVALID_POINTER.
  507. --*/
  508. {
  509. CONFIGRET Status = CR_SUCCESS;
  510. WCHAR tmpString[16], tmpDevice[MAX_DEVICE_ID_LEN];
  511. ULONG PropertyData, DataSize, DataTransferLen, DataType;
  512. UNREFERENCED_PARAMETER(hBinding);
  513. try {
  514. //
  515. // Validate parameters.
  516. //
  517. if (INVALID_FLAGS(ulFlags, 0)) {
  518. Status = CR_INVALID_FLAG;
  519. goto Clean0;
  520. }
  521. if (!ARGUMENT_PRESENT(pulStatus) ||
  522. !ARGUMENT_PRESENT(pulProblem)) {
  523. Status = CR_INVALID_POINTER;
  524. goto Clean0;
  525. }
  526. *pulStatus = 0;
  527. *pulProblem = 0;
  528. if (!IsLegalDeviceId(pDeviceID)) {
  529. Status = CR_INVALID_DEVNODE;
  530. goto Clean0;
  531. }
  532. //
  533. // Retrieve the Flags information from the DeviceNode (which is then
  534. // mapped into status and problem values).
  535. //
  536. Status = GetDeviceStatus(pDeviceID, pulStatus, pulProblem);
  537. if (Status != CR_SUCCESS) {
  538. goto Clean0;
  539. }
  540. //
  541. // Map special flags that aren't stored in the DeviceNode Flags field
  542. //
  543. //
  544. // DN_ROOT_ENUMERATED?
  545. //
  546. lstrcpy(tmpString, pszRegKeyRootEnum);
  547. lstrcat(tmpString, TEXT("\\"));
  548. lstrcpyn(tmpDevice, pDeviceID, lstrlen(tmpString)+1);
  549. if (lstrcmpi(tmpString, tmpDevice) == 0) {
  550. //
  551. // Do not mark PnP BIOS enumerated as ROOT enumerated
  552. //
  553. // Bios enumerated devices look like:
  554. // Root\*aaannnn\PnPBIOS_n
  555. if (lstrlen(pDeviceID) < (4 + 1 + 8 + 1 + 8) ||
  556. _wcsnicmp(&pDeviceID[14], L"PnPBIOS_", 8) != 0 ) {
  557. *pulStatus |= DN_ROOT_ENUMERATED;
  558. }
  559. }
  560. //
  561. // DN_REMOVABLE?
  562. //
  563. DataSize = DataTransferLen = sizeof(ULONG);
  564. if (CR_SUCCESS == PNP_GetDeviceRegProp(NULL,
  565. pDeviceID,
  566. CM_DRP_CAPABILITIES,
  567. &DataType,
  568. (LPBYTE)&PropertyData,
  569. &DataTransferLen,
  570. &DataSize,
  571. 0)) {
  572. if (PropertyData & CM_DEVCAP_REMOVABLE) {
  573. *pulStatus |= DN_REMOVABLE;
  574. }
  575. }
  576. //
  577. // DN_MANUAL?
  578. //
  579. DataSize = DataTransferLen = sizeof(ULONG);
  580. if (CR_SUCCESS != PNP_GetDeviceRegProp(NULL,
  581. pDeviceID,
  582. CM_DRP_CONFIGFLAGS,
  583. &DataType,
  584. (LPBYTE)&PropertyData,
  585. &DataTransferLen,
  586. &DataSize,
  587. 0)) {
  588. PropertyData = 0;
  589. }
  590. if (PropertyData & CONFIGFLAG_MANUAL_INSTALL) {
  591. *pulStatus |= DN_MANUAL;
  592. }
  593. //
  594. // If there isn't already a problem, check to see if the config flags indicate this
  595. // was a failed installation.
  596. //
  597. if (!(*pulStatus & DN_HAS_PROBLEM) && (PropertyData & CONFIGFLAG_FAILEDINSTALL)) {
  598. *pulStatus |= DN_HAS_PROBLEM;
  599. *pulProblem = CM_PROB_FAILED_INSTALL;
  600. }
  601. Clean0:
  602. NOTHING;
  603. } except(EXCEPTION_EXECUTE_HANDLER) {
  604. Status = CR_FAILURE;
  605. }
  606. return Status;
  607. } // PNP_GetDeviceStatus
  608. CONFIGRET
  609. PNP_SetDeviceProblem(
  610. IN handle_t hBinding,
  611. IN LPCWSTR pDeviceID,
  612. IN ULONG ulProblem,
  613. IN ULONG ulFlags
  614. )
  615. /*++
  616. Routine Description:
  617. This is the RPC server entry point for the ConfigManager
  618. CM_Set_DevNode_Problem routines. It set device instance specific
  619. problem information.
  620. Arguments:
  621. hBinding RPC binding handle.
  622. pDeviceID This is a device instance string to retrieve status
  623. information for.
  624. ulProblem A ULONG variable that specifies the Problem
  625. ulFlags May be one of the following two values:
  626. CM_SET_DEVNODE_PROBLEM_NORMAL -- only set problem
  627. if currently no problem
  628. CM_SET_DEVNODE_PROBLEM_OVERRIDE -- override current
  629. problem with new problem
  630. Return Value:
  631. If the function succeeds, the return value is CR_SUCCESS.
  632. If the function fails, the return value is one of the following:
  633. CR_INVALID_DEVNODE,
  634. CR_INVALID_FLAG.
  635. --*/
  636. {
  637. CONFIGRET Status = CR_SUCCESS;
  638. ULONG ulCurrentProblem = 0, ulCurrentStatus = 0;
  639. try {
  640. //
  641. // Verify client privilege
  642. //
  643. if (!VerifyClientAccess(hBinding, &gLuidLoadDriverPrivilege)) {
  644. Status = CR_ACCESS_DENIED;
  645. goto Clean0;
  646. }
  647. //
  648. // Validate parameters
  649. //
  650. if (INVALID_FLAGS(ulFlags, CM_SET_DEVNODE_PROBLEM_BITS)) {
  651. Status = CR_INVALID_FLAG;
  652. goto Clean0;
  653. }
  654. if (!IsLegalDeviceId(pDeviceID)) {
  655. Status = CR_INVALID_DEVNODE;
  656. goto Clean0;
  657. }
  658. //
  659. // If there's already a problem, do nothing unless CM_SET_DEVNODE_PROBLEM_OVERRIDE
  660. // is specified.
  661. //
  662. Status = GetDeviceStatus(pDeviceID, &ulCurrentStatus, &ulCurrentProblem);
  663. if (Status != CR_SUCCESS) {
  664. goto Clean0;
  665. }
  666. if (ulProblem) {
  667. //
  668. // The caller is wanting to set a problem. Make sure that if the device
  669. // already has a problem, it's the same one as we're trying to set (unless
  670. // we're overriding the current problem).
  671. //
  672. if ((ulCurrentStatus & DN_HAS_PROBLEM) &&
  673. (ulCurrentProblem != ulProblem) &&
  674. ((ulFlags & CM_SET_DEVNODE_PROBLEM_BITS) != CM_SET_DEVNODE_PROBLEM_OVERRIDE)) {
  675. Status = CR_FAILURE;
  676. goto Clean0;
  677. }
  678. }
  679. if (!ulProblem) {
  680. Status = ClearDeviceStatus(pDeviceID, DN_HAS_PROBLEM, ulCurrentProblem);
  681. } else {
  682. Status = SetDeviceStatus(pDeviceID, DN_HAS_PROBLEM, ulProblem);
  683. }
  684. Clean0:
  685. NOTHING;
  686. } except(EXCEPTION_EXECUTE_HANDLER) {
  687. Status = CR_FAILURE;
  688. }
  689. return Status;
  690. } // PNP_SetDeviceProblem
  691. CONFIGRET
  692. PNP_UninstallDevInst(
  693. IN handle_t hBinding,
  694. IN LPCWSTR pDeviceID,
  695. IN ULONG ulFlags
  696. )
  697. /*++
  698. Routine Description:
  699. This is the RPC server entry point for the ConfigManager
  700. CM_Deinstall_DevNode routine. It removes the device instance
  701. registry key and any subkeys (only for phantoms).
  702. Arguments:
  703. hBinding RPC binding handle.
  704. pDeviceID The device instance to deinstall.
  705. ulFlags Not used, must be zero.
  706. Return Value:
  707. If the function succeeds, the return value is CR_SUCCESS.
  708. Otherwise it returns one of the CR_ERROR codes.
  709. --*/
  710. {
  711. CONFIGRET Status = CR_SUCCESS;
  712. WCHAR RegStr[MAX_CM_PATH];
  713. ULONG ulCount=0, ulProfile = 0;
  714. ULONG ulStatus, ulProblem;
  715. try {
  716. //
  717. // Verify client privilege
  718. //
  719. if (!VerifyClientAccess(hBinding, &gLuidLoadDriverPrivilege)) {
  720. Status = CR_ACCESS_DENIED;
  721. goto Clean0;
  722. }
  723. //
  724. // Validate parameters
  725. //
  726. if (INVALID_FLAGS(ulFlags, 0)) {
  727. Status = CR_INVALID_FLAG;
  728. goto Clean0;
  729. }
  730. if (!IsLegalDeviceId(pDeviceID)) {
  731. Status = CR_INVALID_DEVNODE;
  732. goto Clean0;
  733. }
  734. //------------------------------------------------------------------
  735. // Uninstall deletes instance key (and all subkeys) for all
  736. // the hardware keys (this means the main Enum branch, the
  737. // config specific keys under HKLM, and the Enum branch under
  738. // HKCU). In the case of the user hardware keys (under HKCU),
  739. // I delete those whether it's a phantom or not, but since
  740. // I can't access the user key from the service side, I have
  741. // to do that part on the client side. For the main hw Enum key
  742. // and the config specific hw keys, I only delete them outright
  743. // if they are phantoms. If not a phantom, then I just make the
  744. // device instance volatile (by saving the original key, deleting
  745. // old key, creating new volatile key and restoring the old
  746. // contents) so at least it will go away during the next boot
  747. //------------------------------------------------------------------
  748. if ((GetDeviceStatus(pDeviceID, &ulStatus, &ulProblem) == CR_SUCCESS) &&
  749. (ulStatus & DN_DRIVER_LOADED)) {
  750. //-------------------------------------------------------------
  751. // device is not a phantom
  752. //-------------------------------------------------------------
  753. if ((ulStatus & DN_ROOT_ENUMERATED)!=0 &&
  754. (ulStatus & DN_DISABLEABLE)==0) {
  755. //
  756. // if a device is root enumerated, but not disableable, it is not uninstallable
  757. // return status is CR_NOT_DISABLEABLE, as that is why it cannot be uninstalled
  758. //
  759. KdPrintEx((DPFLTR_PNPMGR_ID,
  760. DBGF_REGISTRY,
  761. "UMPNPMGR: PNP_UninstallDevInst failed uninstall of %ws (this root device is not disableable)\n",
  762. pDeviceID));
  763. Status = CR_NOT_DISABLEABLE;
  764. } else {
  765. //
  766. // do the volatile-copy-thing
  767. //
  768. KdPrintEx((DPFLTR_PNPMGR_ID,
  769. DBGF_REGISTRY,
  770. "UMPNPMGR: PNP_UninstallDevInst doing volatile key thing on %ws\n",
  771. pDeviceID));
  772. Status = UninstallRealDevice(pDeviceID);
  773. }
  774. } else {
  775. //-------------------------------------------------------------
  776. // device is a phantom
  777. //-------------------------------------------------------------
  778. //
  779. // deregister the device, and delete the registry keys.
  780. //
  781. Status = UninstallPhantomDevice(pDeviceID);
  782. if (Status != CR_SUCCESS) {
  783. goto Clean0;
  784. }
  785. //
  786. // if it is a root enumerated device, we need to reenumerate the
  787. // root so that the PDO will go away, otherwise a new device could
  788. // be created and the root enumerator would get very confused.
  789. //
  790. if (IsDeviceRootEnumerated(pDeviceID)) {
  791. ReenumerateDevInst(pszRegRootEnumerator, FALSE, 0);
  792. }
  793. }
  794. Clean0:
  795. NOTHING;
  796. } except(EXCEPTION_EXECUTE_HANDLER) {
  797. Status = CR_FAILURE;
  798. }
  799. return Status;
  800. } // PNP_UninstallDevInst
  801. CONFIGRET
  802. PNP_AddID(
  803. IN handle_t hBinding,
  804. IN LPCWSTR pszDeviceID,
  805. IN LPCWSTR pszID,
  806. IN ULONG ulFlags
  807. )
  808. /*++
  809. Routine Description:
  810. This is the RPC server entry point for the ConfigManager
  811. CM_Add_ID routine. It adds a hardware or compatible ID to
  812. the registry for this device instance.
  813. Arguments:
  814. hBinding RPC binding handle.
  815. pszDeviceID The device instance to add an ID for.
  816. pszID The hardware or compatible ID to add.
  817. ulFlags Specifies the type of ID to add.
  818. May be one of the following two values:
  819. CM_ADD_ID_HARDWARE -- add hardware ID
  820. CM_ADD_ID_COMPATIBLE -- add compatible ID
  821. Return Value:
  822. If the function succeeds, the return value is CR_SUCCESS.
  823. Otherwise it returns one of the CR_ERROR codes.
  824. --*/
  825. {
  826. CONFIGRET Status = CR_SUCCESS;
  827. WCHAR szCurrentID[REGSTR_VAL_MAX_HCID_LEN];
  828. ULONG ulLength = 0, transferLength, type;
  829. try {
  830. //
  831. // Verify client privilege
  832. //
  833. if (!VerifyClientAccess(hBinding, &gLuidLoadDriverPrivilege)) {
  834. Status = CR_ACCESS_DENIED;
  835. goto Clean0;
  836. }
  837. //
  838. // Validate parameters
  839. //
  840. if (INVALID_FLAGS(ulFlags, CM_ADD_ID_BITS)) {
  841. Status = CR_INVALID_FLAG;
  842. goto Clean0;
  843. }
  844. if (!ARGUMENT_PRESENT(pszID) ||
  845. ((lstrlen(pszID) + 2) > REGSTR_VAL_MAX_HCID_LEN)) {
  846. Status = CR_INVALID_POINTER;
  847. goto Clean0;
  848. }
  849. szCurrentID[0] = L'\0';
  850. transferLength = ulLength = REGSTR_VAL_MAX_HCID_LEN*sizeof(WCHAR);
  851. Status = PNP_GetDeviceRegProp(hBinding,
  852. pszDeviceID,
  853. (ulFlags == CM_ADD_ID_HARDWARE)? CM_DRP_HARDWAREID : CM_DRP_COMPATIBLEIDS,
  854. &type,
  855. (LPBYTE)szCurrentID,
  856. &transferLength,
  857. &ulLength,
  858. 0);
  859. if (Status == CR_SUCCESS) {
  860. if (!MultiSzSearchStringW(szCurrentID, pszID)) {
  861. //
  862. // This ID is not already in the list, so append the new ID
  863. // to the end of the existing IDs and write it back to the
  864. // registry
  865. //
  866. ulLength = REGSTR_VAL_MAX_HCID_LEN*sizeof(WCHAR);
  867. if (MultiSzAppendW(szCurrentID,
  868. &ulLength,
  869. pszID)) {
  870. Status = PNP_SetDeviceRegProp(hBinding,
  871. pszDeviceID,
  872. (ulFlags == CM_ADD_ID_HARDWARE)? CM_DRP_HARDWAREID : CM_DRP_COMPATIBLEIDS,
  873. REG_MULTI_SZ,
  874. (LPBYTE)szCurrentID,
  875. ulLength,
  876. 0);
  877. } else {
  878. //
  879. // Couldn't append the new ID to the multi-sz.
  880. //
  881. Status = CR_FAILURE;
  882. goto Clean0;
  883. }
  884. }
  885. } else {
  886. //
  887. // write out the id with a double null terminator
  888. //
  889. lstrcpy(szCurrentID, pszID);
  890. szCurrentID[lstrlen(pszID)] = L'\0';
  891. szCurrentID[lstrlen(pszID) + 1] = L'\0';
  892. Status = PNP_SetDeviceRegProp(hBinding,
  893. pszDeviceID,
  894. (ulFlags == CM_ADD_ID_HARDWARE)? CM_DRP_HARDWAREID : CM_DRP_COMPATIBLEIDS,
  895. REG_MULTI_SZ,
  896. (LPBYTE)szCurrentID,
  897. (lstrlen(szCurrentID) + 2 ) * sizeof(WCHAR),
  898. 0);
  899. }
  900. Clean0:
  901. NOTHING;
  902. } except(EXCEPTION_EXECUTE_HANDLER) {
  903. Status = CR_FAILURE;
  904. }
  905. return Status;
  906. } // PNP_AddID
  907. CONFIGRET
  908. PNP_RegisterDriver(
  909. IN handle_t hBinding,
  910. IN LPCWSTR pszDeviceID,
  911. IN ULONG ulFlags
  912. )
  913. /*++
  914. Routine Description:
  915. This is the RPC server entry point for the ConfigManager
  916. CM_Register_Device_Driver routine. It setups flags for the
  917. driver/device and enumerates it.
  918. Arguments:
  919. hBinding RPC binding handle.
  920. pszDeviceID The device instance to register the driver for.
  921. ulFlags Flags associated with the driver.
  922. Return Value:
  923. If the function succeeds, the return value is CR_SUCCESS.
  924. Otherwise it returns one of the CR_ERROR codes.
  925. --*/
  926. {
  927. CONFIGRET Status = CR_SUCCESS;
  928. ULONG ulStatusFlag = 0;
  929. try {
  930. //
  931. // Verify client privilege
  932. //
  933. if (!VerifyClientAccess(hBinding, &gLuidLoadDriverPrivilege)) {
  934. Status = CR_ACCESS_DENIED;
  935. goto Clean0;
  936. }
  937. //
  938. // Validate parameters
  939. //
  940. if (INVALID_FLAGS(ulFlags, CM_REGISTER_DEVICE_DRIVER_BITS)) {
  941. Status = CR_INVALID_FLAG;
  942. goto Clean0;
  943. }
  944. if (!IsLegalDeviceId(pszDeviceID)) {
  945. Status = CR_INVALID_DEVNODE;
  946. goto Clean0;
  947. }
  948. SetDeviceStatus(pszDeviceID, ulStatusFlag, 0);
  949. Clean0:
  950. NOTHING;
  951. } except(EXCEPTION_EXECUTE_HANDLER) {
  952. Status = CR_FAILURE;
  953. }
  954. return Status;
  955. } // PNP_RegisterDriver
  956. CONFIGRET
  957. PNP_QueryRemove(
  958. IN handle_t hBinding,
  959. IN LPCWSTR pszDeviceID,
  960. OUT PPNP_VETO_TYPE pVetoType,
  961. OUT LPWSTR pszVetoName,
  962. IN ULONG ulNameLength,
  963. IN ULONG ulFlags
  964. )
  965. /*++
  966. Routine Description:
  967. This is the RPC server entry point for the CM_Query_And_Remove_SubTree
  968. routine.
  969. Arguments:
  970. hBinding RPC binding handle.
  971. pszDeviceID Device instance to query and remove.
  972. ulFlags Specifies flags describing how the query removal
  973. should be processed.
  974. Currently, the following flags are defined:
  975. CM_REMOVE_UI_OK
  976. CM_REMOVE_UI_NOT_OK,
  977. CM_REMOVE_NO_RESTART,
  978. Return Value:
  979. If the function succeeds, the return value is CR_SUCCESS. Otherwise it
  980. returns a CR_ error code.
  981. Note:
  982. Note that this routine actually checks for presence of the CM_REMOVE_* flags,
  983. not the CR_QUERY_REMOVE_* flags. Note that currently the following
  984. CM_QUERY_REMOVE_* and CM_REMOVE_* flags are defined:
  985. CM_QUERY_REMOVE_UI_OK, == CM_REMOVE_UI_OK
  986. CM_QUERY_REMOVE_UI_NOT_OK == CM_REMOVE_UI_NOT_OK
  987. CM_REMOVE_NO_RESTART
  988. Which is why we can simply check for the CM_REMOVE_* flags.
  989. Also, note that currently the CM_REMOVE_UI_OK and CM_REMOVE_UI_NOT_OK flags
  990. are ignored here on the server side. User interface dialogs are displayed
  991. based on whether veto type and veto name buffers are supplied, so the client
  992. has used these flags to determine whether a buffer was to be supplied or not.
  993. --*/
  994. {
  995. CONFIGRET Status = CR_SUCCESS;
  996. try {
  997. //
  998. // Verify client privilege
  999. //
  1000. if (!VerifyClientAccess(hBinding, &gLuidLoadDriverPrivilege)) {
  1001. Status = CR_ACCESS_DENIED;
  1002. goto Clean0;
  1003. }
  1004. //
  1005. // Validate parameters
  1006. //
  1007. if (INVALID_FLAGS(ulFlags, CM_REMOVE_BITS)) {
  1008. Status = CR_INVALID_FLAG;
  1009. goto Clean0;
  1010. }
  1011. if (!IsLegalDeviceId(pszDeviceID) ||
  1012. IsRootDeviceID(pszDeviceID)) {
  1013. Status = CR_INVALID_DEVINST;
  1014. goto Clean0;
  1015. }
  1016. Status = QueryAndRemoveSubTree(pszDeviceID,
  1017. pVetoType,
  1018. pszVetoName,
  1019. ulNameLength,
  1020. (ulFlags & CM_REMOVE_NO_RESTART) ?
  1021. PNP_QUERY_AND_REMOVE_NO_RESTART :
  1022. 0);
  1023. Clean0:
  1024. NOTHING;
  1025. } except(EXCEPTION_EXECUTE_HANDLER) {
  1026. Status = CR_FAILURE;
  1027. }
  1028. return Status;
  1029. } // PNP_QueryRemove
  1030. CONFIGRET
  1031. PNP_DisableDevInst(
  1032. IN handle_t hBinding,
  1033. IN LPCWSTR pszDeviceID,
  1034. OUT PPNP_VETO_TYPE pVetoType,
  1035. OUT LPWSTR pszVetoName,
  1036. IN ULONG ulNameLength,
  1037. IN ULONG ulFlags
  1038. )
  1039. /*++
  1040. Routine Description:
  1041. This is the RPC server entry point for the CM_Disable_DevNode_Ex routine.
  1042. Arguments:
  1043. hBinding RPC binding handle.
  1044. pszDeviceID Device instance to disable.
  1045. ulFlags May specify CM_DISABLE_BITS.
  1046. Return Value:
  1047. If the function succeeds, the return value is CR_SUCCESS. Otherwise it
  1048. returns a CR_ error code.
  1049. Note:
  1050. Note that although the client may supply flags to this routine, they are not
  1051. used.
  1052. --*/
  1053. {
  1054. CONFIGRET Status = CR_SUCCESS;
  1055. try {
  1056. //
  1057. // Verify client privilege
  1058. //
  1059. if (!VerifyClientAccess(hBinding, &gLuidLoadDriverPrivilege)) {
  1060. Status = CR_ACCESS_DENIED;
  1061. goto Clean0;
  1062. }
  1063. //
  1064. // Validate parameters
  1065. //
  1066. if (INVALID_FLAGS(ulFlags, CM_DISABLE_BITS)) {
  1067. Status = CR_INVALID_FLAG;
  1068. goto Clean0;
  1069. }
  1070. if (!IsLegalDeviceId(pszDeviceID) ||
  1071. IsRootDeviceID(pszDeviceID)) {
  1072. Status = CR_INVALID_DEVINST;
  1073. goto Clean0;
  1074. }
  1075. Status = DisableDevInst(pszDeviceID,
  1076. pVetoType,
  1077. pszVetoName,
  1078. ulNameLength);
  1079. Clean0:
  1080. NOTHING;
  1081. } except(EXCEPTION_EXECUTE_HANDLER) {
  1082. Status = CR_FAILURE;
  1083. }
  1084. return Status;
  1085. } // PNP_DisableDevInst
  1086. CONFIGRET
  1087. PNP_RequestDeviceEject(
  1088. IN handle_t hBinding,
  1089. IN LPCWSTR pszDeviceID,
  1090. OUT PPNP_VETO_TYPE pVetoType,
  1091. OUT LPWSTR pszVetoName,
  1092. IN ULONG ulNameLength,
  1093. IN ULONG ulFlags
  1094. )
  1095. {
  1096. CONFIGRET Status = CR_SUCCESS;
  1097. ULONG ulPropertyData, ulDataSize, ulTransferLen, ulDataType;
  1098. BOOL bDockDevice = FALSE;
  1099. try {
  1100. //
  1101. // Validate parameters
  1102. //
  1103. if (INVALID_FLAGS(ulFlags, 0)) {
  1104. Status = CR_INVALID_FLAG;
  1105. goto Clean0;
  1106. }
  1107. if (!IsLegalDeviceId(pszDeviceID)) {
  1108. Status = CR_INVALID_DEVNODE;
  1109. goto Clean0;
  1110. }
  1111. //
  1112. // Do the appropriate security test
  1113. //
  1114. ulDataSize = ulTransferLen = sizeof(ULONG);
  1115. if (CR_SUCCESS == PNP_GetDeviceRegProp(NULL,
  1116. pszDeviceID,
  1117. CM_DRP_CAPABILITIES,
  1118. &ulDataType,
  1119. (LPBYTE)&ulPropertyData,
  1120. &ulTransferLen,
  1121. &ulDataSize,
  1122. 0)) {
  1123. if (ulPropertyData & CM_DEVCAP_DOCKDEVICE) {
  1124. bDockDevice = TRUE;
  1125. }
  1126. }
  1127. if (bDockDevice) {
  1128. //
  1129. // Undocking (ie ejecting a dock) uses a special privilege.
  1130. //
  1131. if ((!IsClientLocal(hBinding)) &&
  1132. (!IsClientAdministrator(hBinding))) {
  1133. //
  1134. // Non-local RPC calls from non-Admins are denied access,
  1135. // regardless of privilege.
  1136. //
  1137. Status = CR_ACCESS_DENIED;
  1138. } else if (!VerifyClientAccess(hBinding, &gLuidUndockPrivilege)) {
  1139. //
  1140. // Callers not posessing the undock privilege are denied access.
  1141. //
  1142. Status = CR_ACCESS_DENIED;
  1143. }
  1144. } else {
  1145. //
  1146. // If the client is not interactive, or is not using the active
  1147. // console session, we require the special load-driver privilege.
  1148. //
  1149. if (!IsClientUsingLocalConsole(hBinding) ||
  1150. !IsClientInteractive(hBinding)) {
  1151. if (!VerifyClientAccess(hBinding, &gLuidLoadDriverPrivilege)) {
  1152. Status = CR_ACCESS_DENIED;
  1153. }
  1154. }
  1155. }
  1156. if (Status != CR_ACCESS_DENIED) {
  1157. //
  1158. // Call kernel-mode to eject the device node
  1159. //
  1160. Status = QueryAndRemoveSubTree(pszDeviceID,
  1161. pVetoType,
  1162. pszVetoName,
  1163. ulNameLength,
  1164. PNP_QUERY_AND_REMOVE_EJECT_DEVICE);
  1165. }
  1166. Clean0:
  1167. NOTHING;
  1168. } except(EXCEPTION_EXECUTE_HANDLER) {
  1169. Status = CR_FAILURE;
  1170. }
  1171. return Status;
  1172. } // PNP_RequestDeviceEject
  1173. //-------------------------------------------------------------------
  1174. // Private functions
  1175. //-------------------------------------------------------------------
  1176. CONFIGRET
  1177. SetupDevInst(
  1178. IN PCWSTR pszDeviceID,
  1179. IN ULONG ulFlags
  1180. )
  1181. /*++
  1182. Routine Description:
  1183. Arguments:
  1184. Return value:
  1185. The return value is CR_SUCCESS if the function suceeds and one of the
  1186. CR_* values if it fails.
  1187. --*/
  1188. {
  1189. CONFIGRET Status = CR_SUCCESS;
  1190. ULONG RegStatus = ERROR_SUCCESS;
  1191. HKEY hKey = NULL;
  1192. ULONG ulStatusFlag=0, ulProblem=0, ulDisableCount=0, ulSize=0;
  1193. PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
  1194. NTSTATUS ntStatus = STATUS_SUCCESS;
  1195. try {
  1196. //
  1197. // Validate parameters
  1198. //
  1199. if (IsRootDeviceID(pszDeviceID)) {
  1200. goto Clean0;
  1201. }
  1202. if (INVALID_FLAGS(ulFlags, CM_SETUP_BITS)) {
  1203. Status = CR_INVALID_FLAG;
  1204. goto Clean0;
  1205. }
  1206. switch(ulFlags) {
  1207. case CM_SETUP_DOWNLOAD:
  1208. case CM_SETUP_WRITE_LOG_CONFS:
  1209. //
  1210. // On NT, these values are a no-op.
  1211. //
  1212. break;
  1213. case CM_SETUP_DEVNODE_READY:
  1214. case CM_SETUP_DEVNODE_RESET:
  1215. if (RegOpenKeyEx(ghEnumKey, pszDeviceID, 0, KEY_READ | KEY_WRITE,
  1216. &hKey) != ERROR_SUCCESS) {
  1217. Status = CR_INVALID_DEVINST;
  1218. goto Clean0;
  1219. }
  1220. //
  1221. // Check the disable count, if greater than zero, do nothing
  1222. //
  1223. ulSize = sizeof(ulDisableCount);
  1224. if (RegQueryValueEx(hKey, pszRegValueDisableCount, NULL, NULL,
  1225. (LPBYTE)&ulDisableCount, &ulSize) == ERROR_SUCCESS) {
  1226. if (ulDisableCount > 0) {
  1227. break;
  1228. }
  1229. }
  1230. GetDeviceStatus(pszDeviceID, &ulStatusFlag, &ulProblem);
  1231. //
  1232. // If there's no problem or if install was done already
  1233. // (immediately) then there's nothing more to do
  1234. //
  1235. if (ulStatusFlag & DN_STARTED) {
  1236. break;
  1237. }
  1238. if (ulStatusFlag & DN_HAS_PROBLEM) {
  1239. //
  1240. // reset the problem and set status to need to enum
  1241. //
  1242. Status = ClearDeviceStatus(pszDeviceID, DN_HAS_PROBLEM, ulProblem);
  1243. }
  1244. if (Status == CR_SUCCESS) {
  1245. //
  1246. // Have kernel-mode pnp manager start the driver/device now.
  1247. // If kernel-mode doesn't have a pdo for this device then it's
  1248. // probably either a Win32 service or a phantom devnode.
  1249. //
  1250. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA));
  1251. RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceID);
  1252. ControlData.Flags = 0;
  1253. if (ulFlags == CM_SETUP_DEVNODE_READY) {
  1254. ntStatus = NtPlugPlayControl(PlugPlayControlStartDevice,
  1255. &ControlData,
  1256. sizeof(ControlData));
  1257. } else {
  1258. ntStatus = NtPlugPlayControl(PlugPlayControlResetDevice,
  1259. &ControlData,
  1260. sizeof(ControlData));
  1261. }
  1262. }
  1263. break;
  1264. case CM_SETUP_PROP_CHANGE:
  1265. //
  1266. // Not sure what Win9x does with this, but it ain't implemented on
  1267. // NT. Let fall through to the default (invalid flag) case...
  1268. //
  1269. default:
  1270. Status = CR_INVALID_FLAG;
  1271. }
  1272. Clean0:
  1273. NOTHING;
  1274. } except(EXCEPTION_EXECUTE_HANDLER) {
  1275. Status = CR_FAILURE;
  1276. }
  1277. if (hKey != NULL) {
  1278. RegCloseKey(hKey);
  1279. }
  1280. return Status;
  1281. } // SetupDevInst
  1282. CONFIGRET
  1283. EnableDevInst(
  1284. IN PCWSTR pszDeviceID
  1285. )
  1286. /*++
  1287. Routine Description:
  1288. This routine performs the server-side work for CM_Enable_DevNode. It
  1289. disables the specified device ID
  1290. Arguments:
  1291. pszDeviceID String that contains the device id to enable
  1292. Return value:
  1293. The return value is CR_SUCCESS if the function suceeds and one of the
  1294. CR_* values if it fails.
  1295. --*/
  1296. {
  1297. CONFIGRET Status = CR_SUCCESS;
  1298. ULONG RegStatus = ERROR_SUCCESS;
  1299. HKEY hKey = NULL;
  1300. WCHAR RegStr[MAX_PATH];
  1301. ULONG ulDisableCount, ulProblem = 0, ulStatus = 0, ulSize;
  1302. try {
  1303. //
  1304. // Verify it isn't the root, can't disable/enable the root. We can
  1305. // probably get rid of this test once we're sure that the root
  1306. // devnode is always marded as not disablable.
  1307. //
  1308. if (IsRootDeviceID(pszDeviceID)) {
  1309. Status = CR_INVALID_DEVINST;
  1310. goto Clean0;
  1311. }
  1312. //
  1313. // Open a key to the specified device instances volatile control key.
  1314. // This is also a partial check whether the device is really present
  1315. // (if so then it has a Control key).
  1316. //
  1317. wsprintf(RegStr, TEXT("%s\\%s"),
  1318. pszDeviceID,
  1319. pszRegKeyDeviceControl);
  1320. if (RegOpenKeyEx(ghEnumKey, RegStr, 0, KEY_READ | KEY_WRITE,
  1321. &hKey) != ERROR_SUCCESS) {
  1322. //
  1323. // NTRAID #174944-2000/08/30-jamesca:
  1324. // Remove dependence on the presence of volatile Control subkey
  1325. // for present devices.
  1326. //
  1327. Status = CR_INVALID_DEVINST;
  1328. goto Clean0;
  1329. }
  1330. //
  1331. // Get the current disable count from the registry
  1332. //
  1333. ulSize = sizeof(ulDisableCount);
  1334. if (RegQueryValueEx(hKey, pszRegValueDisableCount, NULL, NULL,
  1335. (LPBYTE)&ulDisableCount, &ulSize) != ERROR_SUCCESS) {
  1336. //
  1337. // disable count not set yet, assume zero
  1338. //
  1339. ulDisableCount = 0;
  1340. }
  1341. //
  1342. // if the DisableCount is zero, then we're already enabled
  1343. //
  1344. if (ulDisableCount > 0) {
  1345. //
  1346. // Decrement disable count. If the disable count is greater than one,
  1347. // then just return (disable count must drop to zero in order to
  1348. // actually reenable)
  1349. //
  1350. ulDisableCount--;
  1351. RegSetValueEx(hKey, pszRegValueDisableCount, 0, REG_DWORD,
  1352. (LPBYTE)&ulDisableCount, sizeof(ulDisableCount));
  1353. if (ulDisableCount > 0) {
  1354. goto Clean0; // success
  1355. }
  1356. }
  1357. //
  1358. // Retrieve the problem and status values
  1359. //
  1360. if (GetDeviceStatus(pszDeviceID, &ulStatus, &ulProblem) == CR_SUCCESS) {
  1361. //
  1362. // If the problem is only that the device instance is disabled,
  1363. // then reenable it now
  1364. //
  1365. if ((ulStatus & DN_HAS_PROBLEM) && (ulProblem == CM_PROB_DISABLED)) {
  1366. Status = SetupDevInst(pszDeviceID, CM_SETUP_DEVNODE_READY);
  1367. }
  1368. } else {
  1369. //
  1370. // The device isn't currently active or it is a service.
  1371. //
  1372. Status = CR_SUCCESS;
  1373. }
  1374. //
  1375. // For now I'm not doing anything if there was a problem other than
  1376. // not being enabled.
  1377. //
  1378. Clean0:
  1379. NOTHING;
  1380. } except(EXCEPTION_EXECUTE_HANDLER) {
  1381. Status = CR_FAILURE;
  1382. }
  1383. if (hKey != NULL) {
  1384. RegCloseKey(hKey);
  1385. }
  1386. return Status;
  1387. } // EnableDevInst
  1388. CONFIGRET
  1389. DisableDevInst(
  1390. IN PCWSTR pszDeviceID,
  1391. OUT PPNP_VETO_TYPE pVetoType,
  1392. OUT LPWSTR pszVetoName,
  1393. IN ULONG ulNameLength
  1394. )
  1395. /*++
  1396. Routine Description:
  1397. This routine performs the server-side work for CM_Disable_DevNode. It
  1398. disables the specified device ID.
  1399. Arguments:
  1400. pszDeviceID String that contains the device id to disable
  1401. Return value:
  1402. The return value is CR_SUCCESS if the function suceeds and one of the
  1403. CR_* values if it fails.
  1404. --*/
  1405. {
  1406. CONFIGRET Status = CR_SUCCESS;
  1407. ULONG RegStatus = ERROR_SUCCESS;
  1408. HKEY hKey = NULL;
  1409. WCHAR RegStr[MAX_PATH];
  1410. ULONG ulDisableCount=0, ulProblem=0, ulStatus=0, ulSize=0;
  1411. PNP_VETO_TYPE VetoType;
  1412. try {
  1413. //
  1414. // Verify it isn't the root, can't disable/enable the root. We can
  1415. // probably get rid of this test once we're sure that the root
  1416. // devnode is always marded as not disablable.
  1417. //
  1418. if (IsRootDeviceID(pszDeviceID)) {
  1419. Status = CR_INVALID_DEVINST;
  1420. goto Clean0;
  1421. }
  1422. //
  1423. // Open a key to the specified device instances volatile control key.
  1424. // This is also a partial check whether the device is really present
  1425. // (if so then it has a Control key).
  1426. //
  1427. wsprintf(RegStr, TEXT("%s\\%s"),
  1428. pszDeviceID,
  1429. pszRegKeyDeviceControl);
  1430. if (RegOpenKeyEx(ghEnumKey, RegStr, 0, KEY_READ | KEY_WRITE,
  1431. &hKey) != ERROR_SUCCESS) {
  1432. //
  1433. // NTRAID #174944-2000/08/30-jamesca:
  1434. // Remove dependence on the presence of volatile Control subkey
  1435. // for present devices.
  1436. //
  1437. Status = CR_INVALID_DEVINST;
  1438. goto Clean0;
  1439. }
  1440. //
  1441. // Get the current disable count from the registry.
  1442. //
  1443. ulSize = sizeof(ulDisableCount);
  1444. if (RegQueryValueEx(hKey, pszRegValueDisableCount, NULL, NULL,
  1445. (LPBYTE)&ulDisableCount, &ulSize) != ERROR_SUCCESS) {
  1446. //
  1447. // disable count not set yet, assume zero
  1448. //
  1449. ulDisableCount = 0;
  1450. }
  1451. //
  1452. // If the disable count is currently zero, then this is the first
  1453. // disable, so there's work to do. Otherwise, we just increment the
  1454. // disable count and resave it in the registry.
  1455. //
  1456. if (ulDisableCount == 0) {
  1457. //
  1458. // determine if the device instance is stopable
  1459. //
  1460. if (GetDeviceStatus(pszDeviceID, &ulStatus, &ulProblem) == CR_SUCCESS) {
  1461. if (!(ulStatus & DN_DISABLEABLE)) {
  1462. Status = CR_NOT_DISABLEABLE;
  1463. goto Clean0;
  1464. }
  1465. //
  1466. // Attempt to query remove and remove this device instance.
  1467. //
  1468. VetoType = PNP_VetoTypeUnknown;
  1469. Status = QueryAndRemoveSubTree( pszDeviceID,
  1470. &VetoType,
  1471. pszVetoName,
  1472. ulNameLength,
  1473. PNP_QUERY_AND_REMOVE_DISABLE);
  1474. if(pVetoType != NULL) {
  1475. *pVetoType = VetoType;
  1476. }
  1477. if (Status != CR_SUCCESS) {
  1478. if (VetoType == PNP_VetoNonDisableable) {
  1479. //
  1480. // specially handle this Veto case
  1481. // this case is unlikely to occur unless something becomes
  1482. // non-disableable between the status-check and when we
  1483. // try to remove it
  1484. //
  1485. Status = CR_NOT_DISABLEABLE;
  1486. }
  1487. goto Clean0;
  1488. }
  1489. } else {
  1490. //
  1491. // The device isn't active or it is a service.
  1492. //
  1493. Status = CR_SUCCESS;
  1494. }
  1495. }
  1496. //
  1497. // update and save the disable count
  1498. //
  1499. ulDisableCount++;
  1500. RegSetValueEx(hKey, pszRegValueDisableCount, 0, REG_DWORD,
  1501. (LPBYTE)&ulDisableCount, sizeof(ulDisableCount));
  1502. Clean0:
  1503. NOTHING;
  1504. } except(EXCEPTION_EXECUTE_HANDLER) {
  1505. Status = CR_FAILURE;
  1506. }
  1507. if (hKey != NULL) {
  1508. RegCloseKey(hKey);
  1509. }
  1510. return Status;
  1511. } // DisableDevInst
  1512. CONFIGRET
  1513. ReenumerateDevInst(
  1514. IN PCWSTR pszDeviceID,
  1515. IN BOOL EnumSubTree,
  1516. IN ULONG ulFlags
  1517. )
  1518. /*++
  1519. Routine Description:
  1520. This routine performs the server-side work for CM_Reenumerate_DevNode. It
  1521. reenumerates the specified device instance.
  1522. Arguments:
  1523. pszDeviceID String that contains the device id to reenumerate.
  1524. EnumSubTree Specifies whether to reenumerate the entire device subtree.
  1525. ulFlags Any enumeration control flags.
  1526. Return value:
  1527. The return value is CR_SUCCESS if the function suceeds and one of the
  1528. CR_* values if it fails.
  1529. --*/
  1530. {
  1531. CONFIGRET Status = CR_SUCCESS;
  1532. PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
  1533. NTSTATUS ntStatus = STATUS_SUCCESS;
  1534. ULONG ulEnumFlags = 0;
  1535. QI_CONTEXT qiContext;
  1536. //
  1537. // NOTE: For Windows 95, the devnode is marked as needing to be
  1538. // reenumerating (by or'ing StatusFlags with DN_NEED_TO_ENUM), then
  1539. // sometime later, after the initial flurry of reenumeration requests,
  1540. // the whole tree is processed
  1541. //
  1542. if (INVALID_FLAGS(ulFlags, CM_REENUMERATE_BITS)) {
  1543. return CR_INVALID_FLAG;
  1544. }
  1545. try {
  1546. //
  1547. // Attempt to handle this via kernel-mode, if kernel-mode
  1548. // doesn't have a pdo for this device then it's probably either a
  1549. // Win32 service or a phantom devnode.
  1550. //
  1551. if (!EnumSubTree) {
  1552. ulEnumFlags |= PNP_ENUMERATE_DEVICE_ONLY;
  1553. }
  1554. if (ulFlags & CM_REENUMERATE_ASYNCHRONOUS) {
  1555. ulEnumFlags |= PNP_ENUMERATE_ASYNCHRONOUS;
  1556. }
  1557. if (ulFlags & CM_REENUMERATE_RETRY_INSTALLATION) {
  1558. qiContext.HeadNodeSeen = FALSE;
  1559. qiContext.SingleLevelEnumOnly = !EnumSubTree;
  1560. qiContext.Status = CR_SUCCESS;
  1561. Status = EnumerateSubTreeTopDownBreadthFirst(
  1562. NULL,
  1563. pszDeviceID,
  1564. QueueInstallationCallback,
  1565. (PVOID) &qiContext
  1566. );
  1567. if (Status != CR_SUCCESS) {
  1568. return Status;
  1569. }
  1570. if (qiContext.Status != CR_SUCCESS) {
  1571. return qiContext.Status;
  1572. }
  1573. }
  1574. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA));
  1575. RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceID);
  1576. ControlData.Flags = ulEnumFlags;
  1577. ntStatus = NtPlugPlayControl(PlugPlayControlEnumerateDevice,
  1578. &ControlData,
  1579. sizeof(ControlData));
  1580. if (!NT_SUCCESS(ntStatus)) {
  1581. if (ntStatus == STATUS_NO_SUCH_DEVICE) {
  1582. Status = CR_INVALID_DEVNODE; // probably a win32 service
  1583. } else {
  1584. Status = MapNtStatusToCmError(ntStatus);
  1585. }
  1586. }
  1587. } except(EXCEPTION_EXECUTE_HANDLER) {
  1588. Status = CR_FAILURE;
  1589. }
  1590. return Status;
  1591. } // ReenumerateDevInst
  1592. CONFIGRET
  1593. QueryAndRemoveSubTree(
  1594. IN PCWSTR pszDeviceID,
  1595. OUT PPNP_VETO_TYPE pVetoType,
  1596. OUT LPWSTR pszVetoName,
  1597. IN ULONG ulNameLength,
  1598. IN ULONG ulFlags
  1599. )
  1600. /*++
  1601. Routine Description:
  1602. This routine performs the server-side work for CM_Query_Remove_Subtree. It
  1603. determines whether subtree can be removed.
  1604. Arguments:
  1605. pszDeviceID String that contains the device id to query remove
  1606. ulFlags Specifies flags for PLUGPLAY_CONTROL_QUERY_AND_REMOVE_DATA
  1607. May be one of:
  1608. PNP_QUERY_AND_REMOVE_NO_RESTART
  1609. PNP_QUERY_AND_REMOVE_DISABLE
  1610. PNP_QUERY_AND_REMOVE_UNINSTALL
  1611. PNP_QUERY_AND_REMOVE_EJECT_DEVICE
  1612. Return value:
  1613. The return value is CR_SUCCESS if the function suceeds and one of the
  1614. CR_* values if it fails.
  1615. --*/
  1616. {
  1617. CONFIGRET Status = CR_SUCCESS;
  1618. PLUGPLAY_CONTROL_QUERY_AND_REMOVE_DATA ControlData;
  1619. NTSTATUS ntStatus = STATUS_SUCCESS;
  1620. if (ARGUMENT_PRESENT(pVetoType)) {
  1621. *pVetoType = 0;
  1622. }
  1623. if (ARGUMENT_PRESENT(pszVetoName) && (ulNameLength > 0)) {
  1624. *pszVetoName = L'\0';
  1625. }
  1626. //---------------------------------------------------------------------
  1627. // Attempt to handle this via kernel-mode first, if kernel-mode
  1628. // doesn't have a pdo for this device then it's probably either a
  1629. // Win32 service or a phantom devnode, so we'll do the old default
  1630. // Windows NT 4.0 behaviour for now.
  1631. //---------------------------------------------------------------------
  1632. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_QUERY_AND_REMOVE_DATA));
  1633. RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceID);
  1634. ControlData.Flags = ulFlags;
  1635. ControlData.VetoType = PNP_VetoTypeUnknown;
  1636. ControlData.VetoName = pszVetoName;
  1637. ControlData.VetoNameLength = ulNameLength;
  1638. ntStatus = NtPlugPlayControl(PlugPlayControlQueryAndRemoveDevice,
  1639. &ControlData,
  1640. sizeof(ControlData));
  1641. if (!NT_SUCCESS(ntStatus)) {
  1642. if (ntStatus == STATUS_NO_SUCH_DEVICE) {
  1643. Status = CR_INVALID_DEVNODE; // probably a win32 service or legacy driver
  1644. } else if (ntStatus == STATUS_PLUGPLAY_QUERY_VETOED) {
  1645. KdPrintEx((DPFLTR_PNPMGR_ID,
  1646. DBGF_WARNINGS,
  1647. "Query vetoed: Type = %d, Name = %ws\n",
  1648. ControlData.VetoType,
  1649. ControlData.VetoName));
  1650. if (pVetoType != NULL) {
  1651. *pVetoType = ControlData.VetoType;
  1652. }
  1653. if (ARGUMENT_PRESENT(pszVetoName) &&
  1654. (ulNameLength > ControlData.VetoNameLength)) {
  1655. pszVetoName[ControlData.VetoNameLength] = L'\0';
  1656. }
  1657. Status = CR_REMOVE_VETOED;
  1658. } else {
  1659. Status = MapNtStatusToCmError(ntStatus);
  1660. }
  1661. }
  1662. return Status;
  1663. } // QueryRemoveSubTree
  1664. CONFIGRET
  1665. CreateDefaultDeviceInstance(
  1666. IN PCWSTR pszDeviceID,
  1667. IN PCWSTR pszParentID,
  1668. IN BOOL bPhantom,
  1669. IN BOOL bMigrated
  1670. )
  1671. {
  1672. CONFIGRET Status = CR_SUCCESS;
  1673. LONG RegStatus = ERROR_SUCCESS;
  1674. HKEY hKey1 = NULL, hKey2 = NULL;
  1675. WCHAR szBase[MAX_DEVICE_ID_LEN];
  1676. WCHAR szDevice[MAX_DEVICE_ID_LEN];
  1677. WCHAR szInstance[MAX_DEVICE_ID_LEN];
  1678. WCHAR RegStr[MAX_DEVICE_ID_LEN];
  1679. ULONG ulValue=0, ulDisposition=0, i=0;
  1680. UNREFERENCED_PARAMETER(pszParentID);
  1681. //
  1682. // make sure we were specified a valid instance path.
  1683. //
  1684. if (!IsLegalDeviceId(pszDeviceID)) {
  1685. Status = CR_INVALID_DEVNODE;
  1686. goto Clean0;
  1687. }
  1688. //
  1689. // split the supplied instance path into enumerator, device, and instance
  1690. //
  1691. SplitDeviceInstanceString(pszDeviceID, szBase, szDevice, szInstance);
  1692. //
  1693. // open a key to base enumerator (create if doesn't already exist)
  1694. //
  1695. RegStatus = RegCreateKeyEx(ghEnumKey, szBase, 0, NULL,
  1696. REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
  1697. NULL, &hKey2, NULL);
  1698. if (RegStatus != ERROR_SUCCESS) {
  1699. Status = CR_REGISTRY_ERROR;
  1700. goto Clean0;
  1701. }
  1702. //
  1703. // open a key to device (create if doesn't already exist)
  1704. //
  1705. RegStatus = RegCreateKeyEx(hKey2, szDevice, 0, NULL,
  1706. REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
  1707. NULL, &hKey1, NULL);
  1708. if (RegStatus != ERROR_SUCCESS) {
  1709. Status = CR_REGISTRY_ERROR;
  1710. goto CleanupOnFailure;
  1711. }
  1712. RegCloseKey(hKey2); // done with Base Key
  1713. hKey2 = NULL;
  1714. //
  1715. // open a key to instance (if already exists)
  1716. //
  1717. RegStatus = RegOpenKeyEx(hKey1, szInstance, 0, KEY_SET_VALUE, &hKey2);
  1718. //
  1719. // if the key was migrated, an existing instance id should have been
  1720. // supplied. for non-migrated instances, the key should not exist yet.
  1721. //
  1722. if (bMigrated) {
  1723. ASSERT(RegStatus == ERROR_SUCCESS);
  1724. } else {
  1725. ASSERT(RegStatus != ERROR_SUCCESS);
  1726. }
  1727. //
  1728. // if the specified key exists, but the instance is not migrated, find an
  1729. // unused instance value. if a migrated instance was specified, don't
  1730. // bother finding an unused instance - we can just use this one.
  1731. //
  1732. if ((RegStatus == ERROR_SUCCESS) && (!bMigrated)) {
  1733. //
  1734. // find a new instance id to use
  1735. //
  1736. RegCloseKey(hKey2); // done with Instance key
  1737. hKey2 = NULL;
  1738. i = 0;
  1739. while (i <= 9999) {
  1740. wsprintf(szInstance, TEXT("%04u"), i);
  1741. RegStatus = RegOpenKeyEx(hKey1, szInstance, 0, KEY_SET_VALUE, &hKey2);
  1742. if (RegStatus != ERROR_SUCCESS) {
  1743. break; // instance key does not exist, use this instance
  1744. }
  1745. // instance key exists, try next one
  1746. RegCloseKey(hKey2);
  1747. hKey2 = NULL;
  1748. i++;
  1749. }
  1750. if (i > 9999) {
  1751. Status = CR_FAILURE; // we ran out of instances (unlikely)
  1752. goto CleanupOnFailure;
  1753. }
  1754. }
  1755. //
  1756. // open the device instance key
  1757. //
  1758. RegStatus = RegCreateKeyEx(hKey1, szInstance, 0, NULL,
  1759. REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
  1760. NULL, &hKey2, &ulDisposition);
  1761. if (RegStatus != ERROR_SUCCESS) {
  1762. Status = CR_REGISTRY_ERROR;
  1763. goto CleanupOnFailure;
  1764. }
  1765. RegCloseKey(hKey1); // done with device key
  1766. hKey1 = NULL;
  1767. //
  1768. // set the default device instance values
  1769. //
  1770. if (bPhantom) {
  1771. //
  1772. // phantoms are not present by definition
  1773. //
  1774. MarkDevicePhantom(hKey2, TRUE);
  1775. }
  1776. //
  1777. // go ahead and create the volatile Control key at this point.
  1778. //
  1779. RegCreateKeyEx(hKey2, pszRegKeyDeviceControl, 0, NULL,
  1780. REG_OPTION_VOLATILE, KEY_ALL_ACCESS,
  1781. NULL, &hKey1, &ulDisposition);
  1782. RegCloseKey(hKey2); // done with instance key
  1783. hKey2 = NULL;
  1784. goto Clean0; // success
  1785. CleanupOnFailure:
  1786. //
  1787. // attempt to cleanup the device instance (don't delete device or base if
  1788. // other subkeys under it).
  1789. //
  1790. RegDeleteKey(ghEnumKey, pszDeviceID); // delete instance
  1791. wsprintf(RegStr, TEXT("%s\\%s"), szBase, szDevice);
  1792. RegDeleteKey(ghEnumKey, RegStr);
  1793. Clean0:
  1794. if (hKey1 != NULL) {
  1795. RegCloseKey(hKey1);
  1796. }
  1797. if (hKey2 != NULL) {
  1798. RegCloseKey(hKey2);
  1799. }
  1800. return Status;
  1801. } // CreateDefaultDeviceInstance
  1802. ULONG
  1803. GetCurrentConfigFlag(
  1804. IN PCWSTR pDeviceID
  1805. )
  1806. {
  1807. HKEY hKey;
  1808. WCHAR RegStr[MAX_PATH];
  1809. ULONG ulSize = 0, ulCSConfigFlag = 0;
  1810. //
  1811. // open a key to the current hardware profile for this device instance
  1812. //
  1813. wsprintf(RegStr, TEXT("%s\\%s\\%s\\%s"),
  1814. pszRegPathHwProfiles, // System\CCC\Hardware Profiles
  1815. pszRegKeyCurrent, // Current
  1816. pszRegPathEnum, // System\Enum
  1817. pDeviceID);
  1818. if (RegOpenKeyEx(
  1819. HKEY_LOCAL_MACHINE, RegStr, 0, KEY_QUERY_VALUE, &hKey)
  1820. != ERROR_SUCCESS) {
  1821. return 0;
  1822. }
  1823. //
  1824. // retrieve the config specific flag
  1825. //
  1826. ulSize = sizeof(ulCSConfigFlag);
  1827. if (RegQueryValueEx(
  1828. hKey, pszRegValueCSConfigFlags, NULL, NULL,
  1829. (LPBYTE)&ulCSConfigFlag, &ulSize) != ERROR_SUCCESS) {
  1830. //
  1831. // status flags not set yet, assume zero
  1832. //
  1833. ulCSConfigFlag = 0;
  1834. }
  1835. RegCloseKey(hKey);
  1836. return ulCSConfigFlag;
  1837. } // GetCurrentConfigFlag
  1838. BOOL
  1839. MarkDevicePhantom(
  1840. IN HKEY hKey,
  1841. IN ULONG ulValue
  1842. )
  1843. {
  1844. //
  1845. // a phantom device should have a Phantom value of TRUE
  1846. //
  1847. RegSetValueEx(
  1848. hKey, pszRegValuePhantom, 0, REG_DWORD,
  1849. (LPBYTE)&ulValue, sizeof(ULONG));
  1850. return TRUE;
  1851. } // MarkDevicePhantom
  1852. CONFIGRET
  1853. GenerateDeviceInstance(
  1854. OUT LPWSTR pszFullDeviceID,
  1855. IN LPWSTR pszDeviceID,
  1856. IN ULONG ulDevIdLen
  1857. )
  1858. {
  1859. LONG RegStatus = ERROR_SUCCESS;
  1860. WCHAR RegStr[MAX_PATH];
  1861. HKEY hKey;
  1862. ULONG ulInstanceID = 0;
  1863. LPWSTR p;
  1864. //
  1865. // validate the device id component (can't have invalid character or a
  1866. // backslash)
  1867. //
  1868. for (p = pszDeviceID; *p; p++) {
  1869. if (*p <= TEXT(' ') ||
  1870. *p > (WCHAR)0x7F ||
  1871. *p == TEXT('\\')) {
  1872. return CR_INVALID_DEVICE_ID;
  1873. }
  1874. }
  1875. //
  1876. // make sure the supplied buffer is large enough to hold the name of the ROOT
  1877. // enumerator, the supplied device id, a generated instance id ('0000'), two
  1878. // path separator characters, plus a terminating NULL character.
  1879. //
  1880. if (ulDevIdLen < (ULONG)(lstrlen(pszRegKeyRootEnum) +
  1881. lstrlen(pszDeviceID) + 7)) {
  1882. return CR_BUFFER_SMALL;
  1883. }
  1884. lstrcpy(pszFullDeviceID, pszRegKeyRootEnum);
  1885. CharUpper(pszFullDeviceID);
  1886. lstrcat(pszFullDeviceID, TEXT("\\"));
  1887. lstrcat(pszFullDeviceID, pszDeviceID);
  1888. //
  1889. // try opening instance ids until we find one that doesn't already exist
  1890. //
  1891. while (RegStatus == ERROR_SUCCESS && ulInstanceID < 10000) {
  1892. wsprintf(RegStr, TEXT("%s\\%04u"),
  1893. pszFullDeviceID,
  1894. ulInstanceID);
  1895. RegStatus = RegOpenKeyEx(ghEnumKey, RegStr, 0, KEY_QUERY_VALUE, &hKey);
  1896. if (RegStatus == ERROR_SUCCESS) {
  1897. RegCloseKey(hKey);
  1898. ulInstanceID++;
  1899. }
  1900. }
  1901. if (ulInstanceID > 9999) {
  1902. return CR_FAILURE; // instances all used up, seems unlikely
  1903. }
  1904. ASSERT((ULONG)lstrlen(RegStr) < ulDevIdLen);
  1905. lstrcpy(pszFullDeviceID, RegStr);
  1906. return CR_SUCCESS;
  1907. } // GenerateDeviceInstance
  1908. CONFIGRET
  1909. UninstallRealDevice(
  1910. IN LPCWSTR pszDeviceID
  1911. )
  1912. {
  1913. CONFIGRET Status = CR_SUCCESS;
  1914. WCHAR RegStr[MAX_CM_PATH];
  1915. ULONG ulCount = 0, ulProfile = 0;
  1916. //---------------------------------------------------------------------
  1917. // This is the case where a real device id couldn't be stopped, so we
  1918. // cannot really safely delete the device id at this point since the
  1919. // service may still try to use it. Instead, I'll make this device
  1920. // id registry key volatile so that it will eventually go away when
  1921. // the system is shutdown. To make the key volatile, I have to copy
  1922. // it to a temporary spot, delete the original key and recreate it
  1923. // as a volatile key and copy everything back.
  1924. //---------------------------------------------------------------------
  1925. //
  1926. // first, convert the device instance key under the main Enum
  1927. // branch to volatile
  1928. //
  1929. Status = MakeKeyVolatile(pszRegPathEnum, pszDeviceID);
  1930. if (Status != CR_SUCCESS) {
  1931. goto Clean0;
  1932. }
  1933. //
  1934. // next, check each hardware profile and delete any entries for this
  1935. // device instance.
  1936. //
  1937. Status = GetProfileCount(&ulCount);
  1938. if (Status != CR_SUCCESS) {
  1939. goto Clean0;
  1940. }
  1941. for (ulProfile = 1; ulProfile <= ulCount; ulProfile++) {
  1942. wsprintf(RegStr, TEXT("%s\\%04u\\%s"),
  1943. pszRegPathHwProfiles,
  1944. ulProfile,
  1945. pszRegPathEnum);
  1946. //
  1947. // Ignore the status for profile-specific keys since they may
  1948. // not exist.
  1949. //
  1950. MakeKeyVolatile(RegStr, pszDeviceID);
  1951. }
  1952. //
  1953. // finally, mark the device as being removed
  1954. //
  1955. SetDeviceStatus(pszDeviceID, DN_WILL_BE_REMOVED, 0);
  1956. Clean0:
  1957. return Status;
  1958. } // UninstallRealDevice
  1959. CONFIGRET
  1960. UninstallPhantomDevice(
  1961. IN LPCWSTR pszDeviceID
  1962. )
  1963. {
  1964. CONFIGRET Status = CR_SUCCESS;
  1965. NTSTATUS NtStatus = STATUS_SUCCESS;
  1966. PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
  1967. WCHAR szEnumerator[MAX_DEVICE_ID_LEN],
  1968. szDevice[MAX_DEVICE_ID_LEN],
  1969. szInstance[MAX_DEVICE_ID_LEN];
  1970. WCHAR RegStr[MAX_CM_PATH];
  1971. ULONG ulCount = 0, ulProfile = 0;
  1972. //
  1973. // 1. Deregister the original device id (only on phantoms)
  1974. //
  1975. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA));
  1976. RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceID);
  1977. ControlData.Flags = 0;
  1978. NtStatus = NtPlugPlayControl(PlugPlayControlDeregisterDevice,
  1979. &ControlData,
  1980. sizeof(ControlData));
  1981. //
  1982. // Don't bother with the status here, the device might not have
  1983. // been registered which would cause the previous call to fail.
  1984. // Keep trying to clean (uninstall) this device instance.
  1985. //
  1986. //
  1987. // 2. Remove the instance under the main enum branch. If this is the
  1988. // only instance, then the device will be removed as well. The parent
  1989. // key to DeletePrivateKey is the registry path up to the enumerator
  1990. // and the child key is the device and instance.
  1991. //
  1992. //
  1993. // Get the device id's component parts.
  1994. //
  1995. SplitDeviceInstanceString(pszDeviceID,
  1996. szEnumerator,
  1997. szDevice,
  1998. szInstance);
  1999. wsprintf(RegStr, TEXT("%s\\%s"),
  2000. pszRegPathEnum,
  2001. szEnumerator);
  2002. lstrcat(szDevice, TEXT("\\"));
  2003. lstrcat(szDevice, szInstance);
  2004. //
  2005. // delete the device instance key
  2006. //
  2007. Status = DeletePrivateKey(HKEY_LOCAL_MACHINE, RegStr, szDevice);
  2008. if (Status != CR_SUCCESS) {
  2009. goto Clean0;
  2010. }
  2011. //
  2012. // 3. Now check each hardware profile and delete any entries for this
  2013. // device instance.
  2014. //
  2015. Status = GetProfileCount(&ulCount);
  2016. if (Status != CR_SUCCESS) {
  2017. goto Clean0;
  2018. }
  2019. for (ulProfile = 1; ulProfile <= ulCount; ulProfile++) {
  2020. wsprintf(RegStr, TEXT("%s\\%04u\\%s\\%s"),
  2021. pszRegPathHwProfiles,
  2022. ulProfile,
  2023. pszRegPathEnum,
  2024. szEnumerator);
  2025. //
  2026. // Ignore the status for profile-specific keys since they may
  2027. // not exist. RemoveDeviceInstance() will remove the instance
  2028. // and the device if this is the only instance.
  2029. //
  2030. DeletePrivateKey(HKEY_LOCAL_MACHINE, RegStr, szDevice);
  2031. }
  2032. Clean0:
  2033. return Status;
  2034. } // UninstallPhantomDevice
  2035. BOOL
  2036. IsDeviceRootEnumerated(
  2037. IN LPCWSTR pszDeviceID
  2038. )
  2039. {
  2040. WCHAR szEnumerator[MAX_DEVICE_ID_LEN],
  2041. szDevice[MAX_DEVICE_ID_LEN],
  2042. szInstance[MAX_DEVICE_ID_LEN];
  2043. if (!SplitDeviceInstanceString(pszDeviceID,
  2044. szEnumerator,
  2045. szDevice,
  2046. szInstance)) {
  2047. return FALSE;
  2048. }
  2049. return (_wcsicmp(szEnumerator, pszRegKeyRootEnum) == 0);
  2050. } // IsDeviceRootEnumerated
  2051. BOOL
  2052. IsDeviceRegistered(
  2053. IN LPCWSTR pszDeviceID,
  2054. IN LPCWSTR pszService
  2055. )
  2056. {
  2057. WCHAR RegStr[MAX_PATH], szData[MAX_DEVICE_ID_LEN], szValue[MAX_PATH];
  2058. HKEY hKey = NULL;
  2059. LONG RegStatus = ERROR_SUCCESS;
  2060. ULONG ulIndex = 0, ulDataSize = 0, ulValueSize = 0, i = 0;
  2061. BOOL Status = FALSE;
  2062. //
  2063. // open the service's volatile enum registry key
  2064. //
  2065. wsprintf(RegStr, TEXT("%s\\%s"),
  2066. pszService,
  2067. pszRegKeyEnum);
  2068. if (RegOpenKeyEx(ghServicesKey, RegStr, 0, KEY_READ, &hKey)
  2069. == ERROR_SUCCESS) {
  2070. //
  2071. // Enumerate all the values under this key
  2072. //
  2073. while (RegStatus == ERROR_SUCCESS) {
  2074. ulDataSize = MAX_DEVICE_ID_LEN * sizeof(WCHAR);
  2075. ulValueSize = MAX_PATH;
  2076. RegStatus = RegEnumValue(hKey, ulIndex, szValue, &ulValueSize,
  2077. NULL, &i, (LPBYTE)szData, &ulDataSize);
  2078. if (RegStatus == ERROR_SUCCESS) {
  2079. ulIndex++;
  2080. if (lstrcmpi(pszDeviceID, szData) == 0) {
  2081. Status = TRUE;
  2082. break;
  2083. }
  2084. }
  2085. }
  2086. RegCloseKey(hKey);
  2087. }
  2088. return Status;
  2089. } // IsDeviceRegistered
  2090. BOOL
  2091. IsPrivatePhantomFromFirmware(
  2092. IN HKEY hKey
  2093. )
  2094. /*++
  2095. Routine Description:
  2096. This routine checks to see if the supplied device instance registry key is
  2097. for a firmware mapper-created private phantom.
  2098. Arguments:
  2099. hKey - Supplied the handle to the registry key for the device instance to
  2100. be examined.
  2101. Return value:
  2102. If the device instance registry key represents a firmware mapper-reported
  2103. phantom, the return value is TRUE. Otherwise, it is FALSE.
  2104. --*/
  2105. {
  2106. ULONG ValueSize, Value;
  2107. HKEY hControlKey;
  2108. BOOL b = FALSE;
  2109. //
  2110. // First, make sure that this is indeed a phantom
  2111. //
  2112. ValueSize = sizeof(Value);
  2113. Value = 0;
  2114. if((ERROR_SUCCESS != RegQueryValueEx(hKey,
  2115. pszRegValuePhantom,
  2116. NULL,
  2117. NULL,
  2118. (LPBYTE)&Value,
  2119. &ValueSize))
  2120. || !Value)
  2121. {
  2122. //
  2123. // Not a phantom
  2124. //
  2125. goto clean0;
  2126. }
  2127. //
  2128. // OK, we have a phantom--did it come from the firmware mapper?
  2129. //
  2130. ValueSize = sizeof(Value);
  2131. Value = 0;
  2132. if((ERROR_SUCCESS != RegQueryValueEx(hKey,
  2133. pszRegValueFirmwareIdentified,
  2134. NULL,
  2135. NULL,
  2136. (LPBYTE)&Value,
  2137. &ValueSize))
  2138. || !Value)
  2139. {
  2140. //
  2141. // This phantom didn't come from the firmware mapper.
  2142. //
  2143. goto clean0;
  2144. }
  2145. //
  2146. // Finally, we need to check to see whether the device is actually present
  2147. // on this boot. If not, we want to return FALSE, because we don't want
  2148. // detection modules to be registering devnodes for non-existent hardware.
  2149. //
  2150. if(ERROR_SUCCESS == RegOpenKeyEx(hKey,
  2151. pszRegKeyDeviceControl,
  2152. 0,
  2153. KEY_READ,
  2154. &hControlKey)) {
  2155. ValueSize = sizeof(Value);
  2156. Value = 0;
  2157. if((ERROR_SUCCESS == RegQueryValueEx(hControlKey,
  2158. pszRegValueFirmwareMember,
  2159. NULL,
  2160. NULL,
  2161. (LPBYTE)&Value,
  2162. &ValueSize))
  2163. && Value)
  2164. {
  2165. b = TRUE;
  2166. }
  2167. RegCloseKey(hControlKey);
  2168. }
  2169. clean0:
  2170. return b;
  2171. } // IsPrivatePhantomFromFirmware
  2172. CONFIGRET
  2173. EnumerateSubTreeTopDownBreadthFirst(
  2174. IN handle_t BindingHandle,
  2175. IN LPCWSTR DevInst,
  2176. IN PFN_ENUMTREE CallbackFunction,
  2177. IN OUT PVOID Context
  2178. )
  2179. /*++
  2180. Routine Description:
  2181. This routine walks a subtree in a breadth-first nonrecursive manner.
  2182. Arguments:
  2183. BindingHandle RPC Binding handle
  2184. DevInst InstancePath of device to begin with. It is assumed
  2185. that this InstancePath is valid.
  2186. CallbackFunction Function to call for each node in the subtree (DevInst
  2187. included)
  2188. Context Context information to pass to the callback function.
  2189. Return Value:
  2190. CONFIGRET (Success if walk progressed through every node specified by the
  2191. CallbackFunction, failure due to low memory, bad instance path,
  2192. or other problems)
  2193. --*/
  2194. {
  2195. PENUM_ELEMENT enumElement;
  2196. ENUM_ACTION enumAction;
  2197. LIST_ENTRY subTreeHead;
  2198. PLIST_ENTRY listEntry;
  2199. CONFIGRET status;
  2200. //
  2201. // This algorithm is a nonrecursive tree walk. It works by building a list.
  2202. // Parents are removed from the head of the list and their children are
  2203. // added to the end of the list. This enforces a breadth-first downward
  2204. // tree walk.
  2205. //
  2206. InitializeListHead(&subTreeHead);
  2207. //
  2208. // This walk includes the head node as well, so insert it into the list.
  2209. //
  2210. enumElement = HeapAlloc(
  2211. ghPnPHeap,
  2212. 0,
  2213. sizeof(ENUM_ELEMENT) + lstrlen(DevInst)*sizeof(WCHAR)
  2214. );
  2215. if (enumElement == NULL) {
  2216. return CR_OUT_OF_MEMORY;
  2217. }
  2218. lstrcpy(enumElement->DevInst, DevInst);
  2219. InsertTailList(&subTreeHead, &enumElement->ListEntry);
  2220. //
  2221. // Remove each entry from the head of the list on downwards.
  2222. //
  2223. status = CR_SUCCESS;
  2224. while(!IsListEmpty(&subTreeHead)) {
  2225. listEntry = RemoveHeadList(&subTreeHead);
  2226. enumElement = CONTAINING_RECORD(listEntry, ENUM_ELEMENT, ListEntry);
  2227. enumAction = CallbackFunction(enumElement->DevInst, Context);
  2228. if (enumAction == EA_STOP_ENUMERATION) {
  2229. HeapFree(ghPnPHeap, 0, enumElement);
  2230. break;
  2231. }
  2232. if (enumAction != EA_SKIP_SUBTREE) {
  2233. status = EnumerateSubTreeTopDownBreadthFirstWorker(
  2234. BindingHandle,
  2235. enumElement->DevInst,
  2236. &subTreeHead
  2237. );
  2238. if (status != CR_SUCCESS) {
  2239. HeapFree(ghPnPHeap, 0, enumElement);
  2240. break;
  2241. }
  2242. }
  2243. HeapFree(ghPnPHeap, 0, enumElement);
  2244. }
  2245. //
  2246. // There might be entries left in the list if we bailed prematurely. Clean
  2247. // them out here.
  2248. //
  2249. while(!IsListEmpty(&subTreeHead)) {
  2250. listEntry = RemoveHeadList(&subTreeHead);
  2251. enumElement = CONTAINING_RECORD(listEntry, ENUM_ELEMENT, ListEntry);
  2252. HeapFree(ghPnPHeap, 0, enumElement);
  2253. }
  2254. return status;
  2255. }
  2256. CONFIGRET
  2257. EnumerateSubTreeTopDownBreadthFirstWorker(
  2258. IN handle_t BindingHandle,
  2259. IN LPCWSTR DevInst,
  2260. IN OUT PLIST_ENTRY ListHead
  2261. )
  2262. /*++
  2263. Routine Description:
  2264. This routine inserts all the child relations of DevInst onto the passed in
  2265. list.
  2266. Arguments:
  2267. BindingHandle RPC Binding handle
  2268. DevInst InstancePath to enumerate.
  2269. ListHead List to append children to.
  2270. Return Value:
  2271. CONFIGRET
  2272. --*/
  2273. {
  2274. CONFIGRET status;
  2275. ULONG ulLen;
  2276. LPWSTR pszRelations, pszCurEntry;
  2277. PENUM_ELEMENT enumElement;
  2278. status = PNP_GetDeviceListSize(
  2279. BindingHandle,
  2280. DevInst,
  2281. &ulLen,
  2282. CM_GETIDLIST_FILTER_BUSRELATIONS
  2283. );
  2284. if ((status != CR_SUCCESS) || (ulLen == 0)) {
  2285. return status;
  2286. }
  2287. //
  2288. // Allocate an element for the first entry.
  2289. //
  2290. pszRelations = HeapAlloc(
  2291. ghPnPHeap,
  2292. HEAP_ZERO_MEMORY,
  2293. (ulLen+2)*sizeof(WCHAR)
  2294. );
  2295. if (pszRelations == NULL) {
  2296. return CR_OUT_OF_MEMORY;
  2297. }
  2298. status = PNP_GetDeviceList(
  2299. BindingHandle,
  2300. DevInst,
  2301. pszRelations,
  2302. &ulLen,
  2303. CM_GETIDLIST_FILTER_BUSRELATIONS
  2304. );
  2305. if (status != CR_SUCCESS) {
  2306. HeapFree(ghPnPHeap, 0, pszRelations);
  2307. return status;
  2308. }
  2309. for(pszCurEntry = pszRelations;
  2310. *pszCurEntry;
  2311. pszCurEntry = pszCurEntry + lstrlen(pszCurEntry)+1) {
  2312. enumElement = HeapAlloc(
  2313. ghPnPHeap,
  2314. 0,
  2315. sizeof(ENUM_ELEMENT) + lstrlen(pszCurEntry)*sizeof(WCHAR)
  2316. );
  2317. if (enumElement == NULL) {
  2318. HeapFree(ghPnPHeap, 0, pszRelations);
  2319. return CR_OUT_OF_MEMORY;
  2320. }
  2321. //
  2322. // Insert it into the end of the tree.
  2323. //
  2324. lstrcpy(enumElement->DevInst, pszCurEntry);
  2325. InsertTailList(ListHead, &enumElement->ListEntry);
  2326. }
  2327. HeapFree(ghPnPHeap, 0, pszRelations);
  2328. return CR_SUCCESS;
  2329. }