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.

5744 lines
180 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. clasinst.c
  5. Abstract:
  6. Routines for the following 'built-in' class installers:
  7. Keyboard
  8. Mouse
  9. NtApm
  10. DeviceBay
  11. Author:
  12. Lonny McMichael 26-February-1996
  13. Revision History:
  14. 28-Aug-96 Andy Thornton (andrewth)
  15. Added DisableService, IsOnlyKeyboardDriver, RetrieveDriversStatus,
  16. CountDevicesControlled & pSetupAcquireSCMLock routines and modified the
  17. keyboard & mouse class installers to disable the old driver services
  18. under certain circumstances. This is part of a fix for bug R56351 for
  19. NT 4.0 SP1.
  20. 09-Apr-97 Lonny McMichael (lonnym)
  21. Moved pSetupAcquireSCMLock to setupapi and exposed it as a private export.
  22. 19-Jun-97 Jim Cavalaris (t-jcaval)
  23. Added CriticalDeviceCoInstaller co-installer to store the ServiceName
  24. used by devices considered critical to getting the system up into
  25. user mode.
  26. 25-Sep-98 Bryan Willman (bryanwi)
  27. Added apm support.
  28. 11-May-01 Lonny McMichael (lonnym)
  29. Removed support for legacy INFs.
  30. --*/
  31. #include "setupp.h"
  32. #pragma hdrstop
  33. //
  34. // include common INF strings headerfile.
  35. //
  36. #include <infstr.h>
  37. //
  38. // instantiate device class GUIDs.
  39. //
  40. #include <initguid.h>
  41. #include <devguid.h>
  42. #ifdef UNICODE
  43. #define _UNICODE
  44. #endif
  45. #include <tchar.h>
  46. //
  47. // Just to make sure no one is trying to use this obsolete string definition.
  48. //
  49. #ifdef IDS_DEVINSTALL_ERROR
  50. #undef IDS_DEVINSTALL_ERROR
  51. #endif
  52. //
  53. // Some debugging aids for us kernel types
  54. //
  55. //#define CHKPRINT 1
  56. #define CHKPRINT 0
  57. #if CHKPRINT
  58. #define ChkPrintEx(_x_) DbgPrint _x_ // use: ChkPrintEx(( "%x", var, ... ));
  59. #define ChkBreak() DbgBreakPoint()
  60. #else
  61. #define ChkPrintEx(_x_)
  62. #define ChkBreak()
  63. #endif
  64. //
  65. // Declare a string containing the character representation of the Display class GUID.
  66. //
  67. CONST WCHAR szDisplayClassGuid[] = L"{4D36E968-E325-11CE-BFC1-08002BE10318}";
  68. //
  69. // Define a string for the service install section suffix.
  70. //
  71. #define SVCINSTALL_SECTION_SUFFIX (TEXT(".") INFSTR_SUBKEY_SERVICES)
  72. //
  73. // Define the size (in characters) of a GUID string, including terminating NULL.
  74. //
  75. #define GUID_STRING_LEN (39)
  76. //
  77. // Define the string for the load order group for keyboards
  78. //
  79. #define SZ_KEYBOARD_LOAD_ORDER_GROUP TEXT("Keyboard Port")
  80. //
  81. // Define a structure for specifying what Plug&Play driver node is used to install
  82. // a particular service.
  83. //
  84. typedef struct _SERVICE_NODE {
  85. struct _SERVICE_NODE *Next;
  86. WCHAR ServiceName[MAX_SERVICE_NAME_LEN];
  87. DWORD DriverNodeIndex;
  88. } SERVICE_NODE, *PSERVICE_NODE;
  89. //
  90. // Define a structure for specifying a legacy INF that is included in a class driver list.
  91. //
  92. typedef struct _LEGACYINF_NODE {
  93. struct _LEGACYINF_NODE *Next;
  94. WCHAR InfFileName[MAX_PATH];
  95. } LEGACYINF_NODE, *PLEGACYINF_NODE;
  96. //
  97. // Define the context structure used by the critical device co-installer
  98. //
  99. typedef struct _CDC_CONTEXT {
  100. TCHAR OldMatchingDevId[MAX_DEVICE_ID_LEN]; // previous matching device id
  101. TCHAR OldServiceName[MAX_SERVICE_NAME_LEN]; // previous controlling service
  102. // or empty string if none.
  103. } CDC_CONTEXT, *PCDC_CONTEXT;
  104. //
  105. // Strings used in ntapm detection
  106. //
  107. WCHAR rgzMultiFunctionAdapter[] =
  108. L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter";
  109. WCHAR rgzConfigurationData[] = L"Configuration Data";
  110. WCHAR rgzIdentifier[] = L"Identifier";
  111. WCHAR rgzGoodBadKey[] =
  112. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Biosinfo\\APM";
  113. WCHAR rgzGoodBadValue[] =
  114. L"Attributes";
  115. WCHAR rgzAcpiKey[] =
  116. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\ACPI\\Enum";
  117. WCHAR rgzAcpiCount[] =
  118. L"Count";
  119. WCHAR rgzApmLegalHalKey[] =
  120. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ApmLegalHal";
  121. WCHAR rgzApmHalPresent[] =
  122. L"Present";
  123. //
  124. // Internal function prototypes.
  125. //
  126. DWORD
  127. DrvTagToFrontOfGroupOrderList(
  128. IN HDEVINFO DeviceInfoSet,
  129. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  130. );
  131. BOOL
  132. UserBalksAtSharedDrvMsg(
  133. IN HDEVINFO DeviceInfoSet,
  134. IN PSP_DEVINFO_DATA DeviceInfoData,
  135. IN PSP_DEVINSTALL_PARAMS DeviceInstallParams
  136. );
  137. VOID
  138. CopyFixedUpDeviceId(
  139. OUT LPWSTR DestinationString,
  140. IN LPCWSTR SourceString,
  141. IN DWORD SourceStringLen
  142. );
  143. DWORD
  144. PnPInitializationThread(
  145. IN PVOID ThreadParam
  146. );
  147. VOID
  148. MigrateLegacyDisplayDevices(
  149. IN HDEVINFO hDevInfo
  150. );
  151. DWORD
  152. DisableService(
  153. IN LPTSTR ServiceName
  154. );
  155. DWORD
  156. IsKeyboardDriver(
  157. IN PCWSTR ServiceName,
  158. OUT PBOOL pResult
  159. );
  160. DWORD
  161. IsOnlyKeyboardDriver(
  162. IN PCWSTR ServiceName,
  163. OUT PBOOL pResult
  164. );
  165. DWORD
  166. GetServiceStartType(
  167. IN PCWSTR ServiceName
  168. );
  169. LONG
  170. CountDevicesControlled(
  171. IN LPTSTR ServiceName
  172. );
  173. DWORD
  174. InstallNtApm(
  175. IN HDEVINFO DevInfoHandle,
  176. IN BOOLEAN InstallDisabled
  177. );
  178. DWORD
  179. AllowInstallNtApm(
  180. IN HDEVINFO DevInfoHandle,
  181. IN PSP_DEVINFO_DATA DevInfoData OPTIONAL
  182. );
  183. #define NTAPM_NOWORK 0
  184. #define NTAPM_INST_DISABLED 1
  185. #define NTAPM_INST_ENABLED 2
  186. DWORD
  187. DecideNtApm(
  188. VOID
  189. );
  190. #define APM_NOT_PRESENT 0
  191. #define APM_PRESENT_BUT_NOT_USABLE 1
  192. #define APM_ON_GOOD_LIST 2
  193. #define APM_NEUTRAL 3
  194. #define APM_ON_BAD_LIST 4
  195. BOOL
  196. IsProductTypeApmLegal(
  197. VOID
  198. );
  199. DWORD
  200. IsApmPresent(
  201. VOID
  202. );
  203. BOOL
  204. IsAcpiMachine(
  205. VOID
  206. );
  207. BOOL
  208. IsApmLegalHalMachine(
  209. VOID
  210. );
  211. HKEY
  212. OpenCDDRegistryKey(
  213. IN PCTSTR DeviceId,
  214. IN BOOL Create
  215. );
  216. //
  217. // Function definitions
  218. //
  219. BOOL
  220. pInGUISetup(
  221. IN HDEVINFO DeviceInfoSet,
  222. IN PSP_DEVINFO_DATA DeviceInfoData
  223. )
  224. {
  225. SP_DEVINSTALL_PARAMS dip;
  226. ZeroMemory(&dip, sizeof(SP_DEVINSTALL_PARAMS));
  227. dip.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  228. if (SetupDiGetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &dip)) {
  229. if ((dip.Flags & DI_QUIETINSTALL) ||
  230. (dip.FlagsEx & DI_FLAGSEX_IN_SYSTEM_SETUP)) {
  231. return TRUE;
  232. }
  233. else {
  234. return FALSE;
  235. }
  236. }
  237. else {
  238. return FALSE;
  239. }
  240. }
  241. BOOLEAN
  242. MigrateToDevnode(
  243. IN HDEVINFO DeviceInfoSet,
  244. IN PSP_DEVINFO_DATA DeviceInfoData
  245. )
  246. /*++
  247. Routine Description:
  248. This routine will look for a section in the inf that describes what service's
  249. values to migrate up to the new device's devnode. The section's name is
  250. %DecoratedInstallName%.MigrateToDevnode. Under this section the following
  251. entry is looked for:
  252. service-name=value-name[,value-name]...
  253. Each of the value-nanmes are read from
  254. ...\CurrentControlSet\service-name\Parameters and written to the devnode
  255. The primary use of this function is that all of the user modified values are
  256. propagated during upgrade.
  257. Arguments:
  258. DeviceInfoSet - Supplies a handle to the device information set being
  259. acted upon by this install action.
  260. DeviceInfoData - Optionally, supplies the address of a device information
  261. element being acted upon by this install action.
  262. Return Value:
  263. If this function successfully migrates the values listed, it returns TRUE.
  264. If this function cannot successfully migrate the values, then it returns
  265. FALSE.
  266. If this function is being run on a devnode that has already been migrated,
  267. then it returns TRUE.
  268. --*/
  269. {
  270. HKEY hDestination = (HKEY) INVALID_HANDLE_VALUE,
  271. hSource = (HKEY) INVALID_HANDLE_VALUE;
  272. SP_DRVINFO_DETAIL_DATA didd;
  273. SP_DRVINFO_DATA did;
  274. HINF hInf = INVALID_HANDLE_VALUE;
  275. INFCONTEXT infContext;
  276. TCHAR szSectionName[LINE_LEN];
  277. PTCHAR szService = NULL, szServicePath = NULL,
  278. szValueNames = NULL, szCurrentName = NULL;
  279. DWORD dwSize, res, regDataType, regSize, migrated;
  280. BOOLEAN success = FALSE;
  281. PBYTE buffer = NULL;
  282. TCHAR szMigrated[] = L"Migrated";
  283. TCHAR szRegServices[] = L"System\\CurrentControlSet\\Services\\";
  284. TCHAR szParameters[] = L"\\Parameters";
  285. TCHAR szMigrateToDevnode[] = L".MigrateToDevnode";
  286. #define DEFAULT_BUFFER_SIZE 100
  287. if ((hDestination = SetupDiCreateDevRegKey(DeviceInfoSet,
  288. DeviceInfoData,
  289. DICS_FLAG_GLOBAL,
  290. 0,
  291. DIREG_DEV,
  292. NULL,
  293. NULL)) == INVALID_HANDLE_VALUE) {
  294. goto cleanup;
  295. }
  296. dwSize = sizeof(DWORD);
  297. migrated = 0;
  298. if (RegQueryValueEx(hDestination,
  299. szMigrated,
  300. 0,
  301. &regDataType,
  302. (PBYTE) &migrated,
  303. &dwSize) == ERROR_SUCCESS &&
  304. regDataType == REG_DWORD &&
  305. migrated != 0) {
  306. //
  307. // We have migrated to the devnode before (ie a previous upgrade) and
  308. // the user might have changed the respective values, just quit.
  309. //
  310. success = TRUE;
  311. goto cleanup;
  312. }
  313. else {
  314. migrated = TRUE;
  315. RegSetValueEx(hDestination,
  316. szMigrated,
  317. 0,
  318. REG_DWORD,
  319. (PBYTE) &migrated,
  320. sizeof(DWORD));
  321. }
  322. //
  323. // Retrieve information about the driver node selected for this device.
  324. //
  325. did.cbSize = sizeof(SP_DRVINFO_DATA);
  326. if(!SetupDiGetSelectedDriver(DeviceInfoSet, DeviceInfoData, &did)) {
  327. goto cleanup;
  328. }
  329. didd.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  330. if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
  331. DeviceInfoData,
  332. &did,
  333. &didd,
  334. sizeof(didd),
  335. NULL)
  336. && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
  337. //
  338. // For some reason we couldn't get detail data--this should never happen.
  339. //
  340. goto cleanup;
  341. }
  342. //
  343. // Open the INF that installs this driver node, so we can 'pre-run' the AddReg
  344. // entries in its install section.
  345. //
  346. hInf = SetupOpenInfFile(didd.InfFileName,
  347. NULL,
  348. INF_STYLE_WIN4,
  349. NULL
  350. );
  351. if (hInf == INVALID_HANDLE_VALUE) {
  352. //
  353. // For some reason we couldn't open the INF--this should never happen.
  354. //
  355. goto cleanup;
  356. }
  357. SetupDiGetActualSectionToInstall(hInf,
  358. didd.SectionName,
  359. szSectionName,
  360. sizeof(szSectionName) / sizeof(TCHAR),
  361. NULL,
  362. NULL
  363. );
  364. wcscat(szSectionName, szMigrateToDevnode);
  365. if (!SetupFindFirstLine(hInf,
  366. szSectionName,
  367. NULL,
  368. &infContext)) {
  369. goto cleanup;
  370. }
  371. dwSize = 0;
  372. if (SetupGetStringField(&infContext, 0, NULL, 0, &dwSize)) {
  373. //
  374. // Increment the count to hold the null and alloc. The count returned
  375. // is the number of characters in the strings, NOT the number of bytes
  376. // needed.
  377. //
  378. dwSize++;
  379. szService = (PTCHAR) LocalAlloc(LPTR, dwSize * sizeof(TCHAR));
  380. if (!szService ||
  381. !SetupGetStringField(&infContext, 0, szService, dwSize, &dwSize)) {
  382. goto cleanup;
  383. }
  384. }
  385. else {
  386. goto cleanup;
  387. }
  388. dwSize = wcslen(szRegServices)+wcslen(szService)+wcslen(szParameters)+1;
  389. dwSize *= sizeof(TCHAR);
  390. szServicePath = (PTCHAR) LocalAlloc(LPTR, dwSize);
  391. if (!szServicePath) {
  392. res = GetLastError();
  393. goto cleanup;
  394. }
  395. wcscpy(szServicePath, szRegServices);
  396. wcscat(szServicePath, szService);
  397. wcscat(szServicePath, szParameters);
  398. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  399. szServicePath,
  400. 0,
  401. KEY_ALL_ACCESS,
  402. &hSource) != ERROR_SUCCESS) {
  403. goto cleanup;
  404. }
  405. dwSize = 0;
  406. if (SetupGetMultiSzField(&infContext, 1, NULL, 0, &dwSize)) {
  407. //
  408. // Increment the count to hold the null and alloc. The count returned
  409. // is the number of characters in the strings, NOT the number of bytes
  410. // needed.
  411. //
  412. dwSize++;
  413. szValueNames = (PTCHAR) LocalAlloc(LPTR, dwSize * sizeof(TCHAR));
  414. if (!szValueNames ||
  415. !SetupGetMultiSzField(&infContext, 1, szValueNames, dwSize, &dwSize)) {
  416. goto cleanup;
  417. }
  418. }
  419. else {
  420. goto cleanup;
  421. }
  422. regSize = dwSize = DEFAULT_BUFFER_SIZE;
  423. buffer = (PBYTE) LocalAlloc(LPTR, regSize);
  424. if (!buffer) {
  425. goto cleanup;
  426. }
  427. for (szCurrentName = szValueNames;
  428. *szCurrentName;
  429. regSize = dwSize, szCurrentName += wcslen(szCurrentName) + 1) {
  430. getbits:
  431. res = RegQueryValueEx(hSource,
  432. szCurrentName,
  433. 0,
  434. &regDataType,
  435. (PBYTE) buffer,
  436. &regSize);
  437. if (res == ERROR_MORE_DATA) {
  438. //
  439. // regSize contains new buffer size, free and reallocate
  440. //
  441. dwSize = regSize;
  442. LocalFree(buffer);
  443. buffer = LocalAlloc(LPTR, dwSize);
  444. if (buffer) {
  445. goto getbits;
  446. }
  447. else {
  448. goto cleanup;
  449. }
  450. }
  451. else if (res == ERROR_SUCCESS) {
  452. RegSetValueEx(hDestination,
  453. szCurrentName,
  454. 0,
  455. regDataType,
  456. buffer,
  457. regSize);
  458. }
  459. }
  460. success = TRUE;
  461. cleanup:
  462. //
  463. // Clean up and leave
  464. //
  465. if (hInf != (HKEY) INVALID_HANDLE_VALUE) {
  466. SetupCloseInfFile(hInf);
  467. }
  468. if (hDestination != (HKEY) INVALID_HANDLE_VALUE) {
  469. RegCloseKey(hDestination);
  470. }
  471. if (hSource != (HKEY) INVALID_HANDLE_VALUE) {
  472. RegCloseKey(hSource);
  473. }
  474. if (buffer) {
  475. LocalFree(buffer);
  476. }
  477. if (szService) {
  478. LocalFree(szService);
  479. }
  480. if (szServicePath) {
  481. LocalFree(szServicePath);
  482. }
  483. if (szValueNames) {
  484. LocalFree(szValueNames);
  485. }
  486. return success;
  487. }
  488. void
  489. MarkDriverNodesBad(
  490. IN HDEVINFO DeviceInfoSet,
  491. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  492. IN DWORD DriverType
  493. )
  494. {
  495. SP_DRVINSTALL_PARAMS drvInstallParams;
  496. SP_DRVINFO_DATA drvData;
  497. ULONG index = 0;
  498. //
  499. // Only mark driver nodes as bad during gui setup
  500. //
  501. if (!pInGUISetup(DeviceInfoSet, DeviceInfoData)) {
  502. return;
  503. }
  504. if (SetupDiBuildDriverInfoList(DeviceInfoSet, DeviceInfoData, DriverType))
  505. {
  506. ZeroMemory(&drvData, sizeof(SP_DRVINFO_DATA));
  507. drvData.cbSize = sizeof(SP_DRVINFO_DATA);
  508. while (SetupDiEnumDriverInfo(DeviceInfoSet,
  509. DeviceInfoData,
  510. DriverType,
  511. index++,
  512. &drvData)) {
  513. if (drvData.DriverVersion == 0) {
  514. ZeroMemory(&drvInstallParams, sizeof(SP_DRVINSTALL_PARAMS));
  515. drvInstallParams.cbSize = sizeof(SP_DRVINSTALL_PARAMS);
  516. if (SetupDiGetDriverInstallParams(DeviceInfoSet,
  517. DeviceInfoData,
  518. &drvData,
  519. &drvInstallParams))
  520. {
  521. drvInstallParams.Flags |= DNF_BAD_DRIVER;
  522. SetupDiSetDriverInstallParams(DeviceInfoSet,
  523. DeviceInfoData,
  524. &drvData,
  525. &drvInstallParams);
  526. }
  527. }
  528. ZeroMemory(&drvData, sizeof(SP_DRVINFO_DATA));
  529. drvData.cbSize = sizeof(SP_DRVINFO_DATA);
  530. }
  531. }
  532. }
  533. DWORD
  534. ConfirmWHQLInputRequirements(
  535. IN HDEVINFO DeviceInfoSet,
  536. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  537. IN LPTSTR Services,
  538. IN LPCTSTR CompatInfName,
  539. IN DI_FUNCTION InstallFunction
  540. )
  541. /*++
  542. Routine Description:
  543. This function enforces the WHQL requirements that a 3rd party vendor or OEM
  544. cannot replace the ImagePath of the input drivers (mouclass.sys for instance).
  545. This does not stop the OEMs from disabling our drivers and installing their
  546. own services though.
  547. Arguments:
  548. DeviceInfoSet - Supplies a handle to the device information set being
  549. acted upon by this install action.
  550. DeviceInfoData - Optionally, supplies the address of a device information
  551. element being acted upon by this install action.
  552. Services - A multi-sz of service names to check
  553. CompatInfName - name of the system inf to set the match to if we detect an
  554. an INF that is actually trying to replace an image
  555. InstallFunction - The InstallFunction for which this function was called for.
  556. The function does different things if InstallFunction is equal to
  557. DIF_SELECTBESTCOMPATDRV.
  558. Return Value:
  559. If this function determines that the INF in question matches the WHQL
  560. requirement, returns ERROR_DI_DO_DEFAULT
  561. If the default determines that the INF violates the requirements and we find
  562. a match, returns NO_ERROR
  563. If the default determines that the INF violates the requirements and we
  564. don't find a match or the InstallFunction is not select best compat drv,
  565. returns ERROR_DI_DONT_INSTALL.
  566. If an error occurred while attempting to perform the requested action, a
  567. Win32 error code is returned (via GetLastError)
  568. --*/
  569. {
  570. HINF hInf;
  571. SP_DRVINFO_DATA drvData;
  572. SP_DRVINFO_DETAIL_DATA drvDetData;
  573. DWORD dwSize;
  574. TCHAR szSection[LINE_LEN],
  575. szNewService[LINE_LEN],
  576. szBinary[LINE_LEN],
  577. szServiceInstallSection[LINE_LEN];
  578. LPTSTR szCurrentService;
  579. INFCONTEXT infContext, infContextService;
  580. DWORD ret = ERROR_DI_DO_DEFAULT;
  581. BOOLEAN badServiceEntry = FALSE;
  582. if (InstallFunction == DIF_SELECTBESTCOMPATDRV) {
  583. MarkDriverNodesBad(DeviceInfoSet, DeviceInfoData, SPDIT_COMPATDRIVER);
  584. if (!SetupDiSelectBestCompatDrv(DeviceInfoSet, DeviceInfoData)) {
  585. return GetLastError();
  586. }
  587. }
  588. ZeroMemory(&drvData, sizeof(SP_DRVINFO_DATA));
  589. drvData.cbSize = sizeof(SP_DRVINFO_DATA);
  590. if (!SetupDiGetSelectedDriver(DeviceInfoSet, DeviceInfoData, &drvData)) {
  591. return GetLastError();
  592. }
  593. ZeroMemory(&drvDetData, sizeof(SP_DRVINFO_DETAIL_DATA));
  594. drvDetData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  595. if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
  596. DeviceInfoData,
  597. &drvData,
  598. &drvDetData,
  599. drvDetData.cbSize,
  600. &dwSize) &&
  601. GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  602. return GetLastError();
  603. }
  604. hInf = SetupOpenInfFile(drvDetData.InfFileName,
  605. NULL,
  606. INF_STYLE_WIN4,
  607. NULL);
  608. if (hInf == INVALID_HANDLE_VALUE) {
  609. return ERROR_DI_DO_DEFAULT;
  610. }
  611. //
  612. // Get the actual section name so we can find the .Services section
  613. //
  614. if (!SetupDiGetActualSectionToInstall(hInf,
  615. drvDetData.SectionName,
  616. szSection,
  617. sizeof(szSection) / sizeof(TCHAR),
  618. NULL,
  619. NULL) &&
  620. GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  621. ret = GetLastError();
  622. goto Done;
  623. }
  624. lstrcat(szSection, TEXT(".Services"));
  625. if (SetupFindFirstLine(hInf, szSection, TEXT("AddService"), &infContext)) {
  626. do {
  627. //
  628. // Get the name of the service to install
  629. //
  630. dwSize = LINE_LEN;
  631. if (!SetupGetStringField(&infContext,
  632. 1,
  633. szNewService,
  634. dwSize,
  635. &dwSize)) {
  636. continue;
  637. }
  638. _tcsupr(szNewService);
  639. for (szCurrentService = Services;
  640. *szCurrentService;
  641. szCurrentService += lstrlen(szCurrentService) + 1) {
  642. if (lstrcmp(szCurrentService, szNewService) != 0)
  643. continue;
  644. dwSize = LINE_LEN;
  645. if (!SetupGetStringField(&infContext,
  646. 3,
  647. szServiceInstallSection,
  648. dwSize,
  649. &dwSize)) {
  650. continue;
  651. }
  652. if (!SetupFindFirstLine(hInf,
  653. szServiceInstallSection,
  654. TEXT("ServiceBinary"),
  655. &infContextService)) {
  656. //
  657. // If no ServiceBinary is present, the system looks for a .sys with the
  658. // same name as the service so we are OK
  659. //
  660. continue;
  661. }
  662. //
  663. // Get the actual binary's image name
  664. //
  665. dwSize = LINE_LEN;
  666. if (!SetupGetStringField(&infContextService,
  667. 1,
  668. szBinary,
  669. dwSize,
  670. &dwSize)) {
  671. //
  672. // couldn't get the name, assume the worst
  673. //
  674. badServiceEntry = TRUE;
  675. }
  676. else {
  677. _tcsupr(szBinary);
  678. if (_tcsstr(szBinary, szNewService) == NULL) {
  679. //
  680. // The service name is NOT the same as the binary's name
  681. //
  682. badServiceEntry = TRUE;
  683. }
  684. }
  685. //
  686. // No need to continue searching the list, we already found our
  687. // match
  688. //
  689. break;
  690. }
  691. if (badServiceEntry) {
  692. SP_DRVINFO_DATA drvDataAlt;
  693. SP_DRVINFO_DETAIL_DATA drvDetDataAlt;
  694. TCHAR szFmt[256];
  695. TCHAR szMsgTxt[256];
  696. int i = 0;
  697. ret = ERROR_DI_DONT_INSTALL;
  698. SetupOpenLog(FALSE);
  699. if (InstallFunction != DIF_SELECTBESTCOMPATDRV) {
  700. //
  701. // We will try to pick a better one if we find new hardware,
  702. // but for the update driver / manual install case,
  703. // fail it!
  704. //
  705. LoadString(MyModuleHandle,
  706. IDS_FAIL_INPUT_WHQL_REQS,
  707. szFmt,
  708. SIZECHARS(szFmt));
  709. wsprintf(szMsgTxt, szFmt, drvDetData.InfFileName, szNewService);
  710. SetupLogError(szMsgTxt, LogSevError);
  711. SetupCloseLog();
  712. break;
  713. }
  714. //
  715. // We should have a match in the system provided inf
  716. //
  717. drvDataAlt.cbSize = sizeof(SP_DRVINFO_DATA);
  718. while (SetupDiEnumDriverInfo(DeviceInfoSet,
  719. DeviceInfoData,
  720. SPDIT_COMPATDRIVER,
  721. i++,
  722. &drvDataAlt)) {
  723. PTCHAR name;
  724. drvDetDataAlt.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  725. if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
  726. DeviceInfoData,
  727. &drvDataAlt,
  728. &drvDetDataAlt,
  729. drvDetDataAlt.cbSize,
  730. &dwSize) &&
  731. GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  732. //
  733. // Do something here!
  734. //
  735. // return GetLastError();
  736. }
  737. //
  738. // Find just the inf file name w/out the path
  739. //
  740. name = drvDetDataAlt.InfFileName;
  741. while (*name)
  742. name++;
  743. while (*name != TEXT('\\') && name != drvDetDataAlt.InfFileName)
  744. name--;
  745. if (*name == TEXT('\\'))
  746. name++;
  747. if (lstrcmpi(name, CompatInfName) == 0) {
  748. //
  749. // Set the known good entry as the selected device
  750. //
  751. SetupDiSetSelectedDriver(DeviceInfoSet,
  752. DeviceInfoData,
  753. &drvDataAlt);
  754. ret = ERROR_SUCCESS;
  755. break;
  756. }
  757. }
  758. if (ret == ERROR_SUCCESS) {
  759. LoadString(MyModuleHandle,
  760. IDS_FAIL_INPUT_WHQL_REQS_AVERTED,
  761. szFmt,
  762. SIZECHARS(szFmt));
  763. wsprintf(szMsgTxt, szFmt, drvDetData.InfFileName,
  764. szNewService, CompatInfName);
  765. }
  766. else {
  767. LoadString(MyModuleHandle,
  768. IDS_FAIL_INPUT_WHQL_REQS_NO_ALT,
  769. szFmt,
  770. SIZECHARS(szFmt));
  771. wsprintf(szMsgTxt, szFmt, drvDetData.InfFileName,
  772. szNewService, CompatInfName);
  773. }
  774. SetupLogError(szMsgTxt, LogSevWarning);
  775. SetupCloseLog();
  776. break;
  777. }
  778. } while (SetupFindNextMatchLine(&infContext, TEXT("AddService"), &infContext));
  779. }
  780. Done:
  781. SetupCloseInfFile(hInf);
  782. return ret;
  783. }
  784. #define InputClassOpenLog() SetupOpenLog(FALSE)
  785. #define InputClassCloseLog() SetupCloseLog()
  786. BOOL CDECL
  787. InputClassLogError(
  788. LogSeverity Severity,
  789. TCHAR *MsgFormat,
  790. ...
  791. )
  792. /*++
  793. Outputs a message to the setup log. Prepends "Input Install: " to the
  794. strings and appends the correct newline chars (\r\n)
  795. --*/
  796. {
  797. int cch;
  798. TCHAR ach[MAX_PATH+4]; // Largest path plus extra
  799. va_list vArgs;
  800. BOOL result;
  801. InputClassOpenLog();
  802. *ach = 0;
  803. wsprintf(&ach[0], TEXT("Input Install: "));
  804. cch = lstrlen(ach);
  805. va_start(vArgs, MsgFormat);
  806. wvnsprintf(&ach[cch], MAX_PATH-cch, MsgFormat, vArgs);
  807. lstrcat(ach, TEXT("\r\n"));
  808. va_end(vArgs);
  809. result = SetupLogError(ach, Severity);
  810. InputClassCloseLog();
  811. return result;
  812. }
  813. TCHAR szPS2Driver[] = TEXT("i8042prt");
  814. VOID
  815. FixUpPS2Mouse(
  816. IN HDEVINFO DeviceInfoSet,
  817. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  818. IN LPCTSTR NewServiceName
  819. )
  820. {
  821. HKEY hDevnode, hKeySystem;
  822. DWORD dwSize, dwDetect = 0, dwType,ns;
  823. TCHAR szDetect[] = TEXT("EnableWheelDetection");
  824. TCHAR szBadBios[] = TEXT("PS2_Inst.NoInterruptInit.Bioses");
  825. TCHAR szSection[] = TEXT("PS2_Inst.NoInterruptInit");
  826. TCHAR szDescSystem[] = TEXT("HARDWARE\\DESCRIPTION\\SYSTEM");
  827. TCHAR szSystemBiosVersion[] = TEXT("SystemBiosVersion");
  828. PTCHAR szBadBiosNames = NULL,
  829. szCurrentBadName,
  830. szBiosNames = NULL,
  831. szCurrentBiosName,
  832. szSystemDesc;
  833. SP_DRVINFO_DETAIL_DATA didd;
  834. SP_DRVINFO_DATA did;
  835. BOOL bad;
  836. HINF hInf = INVALID_HANDLE_VALUE;
  837. INFCONTEXT infContext;
  838. if (lstrcmpi(NewServiceName, szPS2Driver) != 0) {
  839. InputClassLogError(LogSevInformation, TEXT("Not a PS2 device."));
  840. return;
  841. }
  842. hDevnode = SetupDiOpenDevRegKey(DeviceInfoSet,
  843. DeviceInfoData,
  844. DICS_FLAG_GLOBAL,
  845. 0,
  846. DIREG_DEV,
  847. KEY_ALL_ACCESS);
  848. if (hDevnode == INVALID_HANDLE_VALUE) {
  849. return;
  850. }
  851. //
  852. // We are forcing the wheel detection to assume wheel is present for i8042prt.
  853. // If we get negative feedback from this, we will remove this code, other-
  854. // wise this will save us the hassle of OEM wheel mice that we
  855. // can't detect at all.
  856. //
  857. dwSize = sizeof(DWORD);
  858. if (RegQueryValueEx(hDevnode,
  859. szDetect,
  860. NULL,
  861. NULL,
  862. (PBYTE) &dwDetect,
  863. &dwSize) != ERROR_SUCCESS || dwDetect == 1) {
  864. dwDetect = 2;
  865. RegSetValueEx(hDevnode,
  866. szDetect,
  867. 0,
  868. REG_DWORD,
  869. (PBYTE) &dwDetect,
  870. sizeof(DWORD));
  871. }
  872. //
  873. // See if this system can't handle init via the interrupt
  874. //
  875. //
  876. // Get the system bios description (a multi sz)
  877. //
  878. dwSize = 0;
  879. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  880. szDescSystem,
  881. 0,
  882. KEY_READ,
  883. &hKeySystem) != ERROR_SUCCESS ||
  884. RegQueryValueEx(hKeySystem,
  885. szSystemBiosVersion,
  886. NULL,
  887. NULL,
  888. NULL,
  889. &dwSize) != ERROR_SUCCESS || dwSize == 0) {
  890. goto finished;
  891. }
  892. dwSize++;
  893. szBiosNames = (PTCHAR) LocalAlloc(LPTR, dwSize * sizeof(TCHAR));
  894. dwType = 0;
  895. if (!szBiosNames ||
  896. RegQueryValueEx(hKeySystem,
  897. szSystemBiosVersion,
  898. NULL,
  899. &dwType,
  900. (PBYTE) szBiosNames,
  901. &dwSize) != ERROR_SUCCESS || dwType != REG_MULTI_SZ) {
  902. goto finished;
  903. }
  904. //
  905. // Retrieve information about the driver node selected for this device.
  906. //
  907. did.cbSize = sizeof(SP_DRVINFO_DATA);
  908. if(!SetupDiGetSelectedDriver(DeviceInfoSet, DeviceInfoData, &did)) {
  909. goto finished;
  910. }
  911. didd.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  912. if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
  913. DeviceInfoData,
  914. &did,
  915. &didd,
  916. sizeof(didd),
  917. NULL)
  918. && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
  919. //
  920. // For some reason we couldn't get detail data--this should never happen.
  921. //
  922. InputClassLogError(LogSevInformation, TEXT("Couldn't get driver info detail."));
  923. goto finished;
  924. }
  925. //
  926. // Open the INF that installs this driver node, so we can 'pre-run' the AddReg
  927. // entries in its install section.
  928. //
  929. hInf = SetupOpenInfFile(didd.InfFileName,
  930. NULL,
  931. INF_STYLE_WIN4,
  932. NULL);
  933. if (hInf == INVALID_HANDLE_VALUE) {
  934. //
  935. // For some reason we couldn't open the INF--this should never happen.
  936. //
  937. InputClassLogError(LogSevInformation, TEXT("Couldn't open inf."));
  938. goto finished;
  939. }
  940. dwSize = 0;
  941. if (!SetupFindFirstLine(hInf, szBadBios, NULL, &infContext) ||
  942. !SetupGetMultiSzField(&infContext, 1, NULL, 0, &dwSize)) {
  943. goto finished;
  944. }
  945. //
  946. // Increment the count to hold the null and alloc. The count returned
  947. // is the number of characters in the strings, NOT the number of bytes
  948. // needed.
  949. //
  950. dwSize++;
  951. szBadBiosNames = (PTCHAR) LocalAlloc(LPTR, dwSize * sizeof(TCHAR));
  952. if (!szBadBiosNames ||
  953. !SetupGetMultiSzField(&infContext, 1, szBadBiosNames, dwSize, &dwSize)) {
  954. goto finished;
  955. }
  956. bad = FALSE;
  957. for (szCurrentBadName = szBadBiosNames;
  958. *szCurrentBadName;
  959. szCurrentBadName += wcslen(szCurrentBadName) + 1) {
  960. _tcsupr(szCurrentBadName);
  961. for (szCurrentBiosName = szBiosNames;
  962. *szCurrentBiosName;
  963. szCurrentBiosName += wcslen(szCurrentBiosName) + 1) {
  964. if (szCurrentBadName == szBadBiosNames) {
  965. _tcsupr(szCurrentBiosName);
  966. }
  967. if (_tcsstr(szCurrentBiosName, szCurrentBadName)) {
  968. bad =
  969. SetupInstallFromInfSection(NULL,
  970. hInf,
  971. szSection,
  972. SPINST_REGISTRY,
  973. hDevnode,
  974. NULL,
  975. 0,
  976. NULL,
  977. NULL,
  978. DeviceInfoSet,
  979. DeviceInfoData);
  980. break;
  981. }
  982. }
  983. if (bad) {
  984. break;
  985. }
  986. }
  987. finished:
  988. if (szBiosNames) {
  989. LocalFree(szBiosNames);
  990. szBiosNames = NULL;
  991. }
  992. if (szBadBiosNames) {
  993. LocalFree(szBadBiosNames);
  994. szBadBiosNames = NULL;
  995. }
  996. if (hInf != INVALID_HANDLE_VALUE) {
  997. SetupCloseInfFile(hInf);
  998. hInf = INVALID_HANDLE_VALUE;
  999. }
  1000. if (hDevnode != INVALID_HANDLE_VALUE) {
  1001. RegCloseKey(hDevnode);
  1002. hDevnode = INVALID_HANDLE_VALUE;
  1003. }
  1004. if (hKeySystem != INVALID_HANDLE_VALUE) {
  1005. RegCloseKey(hKeySystem);
  1006. hKeySystem = INVALID_HANDLE_VALUE;
  1007. }
  1008. }
  1009. TCHAR szMouclassParameters[] = TEXT("System\\CurrentControlSet\\Services\\Mouclass\\Parameters");
  1010. TCHAR szNativeMouseInf[] = TEXT("msmouse.inf");
  1011. TCHAR szNativeMouseServices[] =
  1012. TEXT("MOUCLASS\0")
  1013. TEXT("I8042PRT\0")
  1014. TEXT("SERMOUSE\0")
  1015. TEXT("MOUHID\0")
  1016. TEXT("INPORT\0")
  1017. TEXT("\0");
  1018. typedef struct _MULTI_SZ {
  1019. LPTSTR String;
  1020. DWORD Size;
  1021. } MULTI_SZ, *PMULTI_SZ;
  1022. typedef struct _FILTERS {
  1023. MULTI_SZ Lower;
  1024. MULTI_SZ Upper;
  1025. } FILTERS, *PFILTERS;
  1026. void GetFilterInfo(
  1027. IN HDEVINFO DeviceInfoSet,
  1028. IN PSP_DEVINFO_DATA DeviceInfoData,
  1029. IN DWORD Property,
  1030. OUT PMULTI_SZ MultiSz
  1031. )
  1032. {
  1033. BOOL res;
  1034. DWORD gle;
  1035. ZeroMemory(MultiSz, sizeof(MULTI_SZ));
  1036. //
  1037. // Will return FALSE and set the last error to insufficient buffer if
  1038. // this property is present.
  1039. //
  1040. res = SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  1041. DeviceInfoData,
  1042. Property,
  1043. NULL,
  1044. NULL,
  1045. 0,
  1046. &MultiSz->Size);
  1047. if (res == FALSE && GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
  1048. MultiSz->Size > 0) {
  1049. MultiSz->String = (LPTSTR) LocalAlloc(LPTR, MultiSz->Size);
  1050. if (MultiSz->String) {
  1051. if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  1052. DeviceInfoData,
  1053. Property,
  1054. NULL,
  1055. (PBYTE) MultiSz->String,
  1056. MultiSz->Size,
  1057. NULL)) {
  1058. LocalFree(MultiSz->String);
  1059. MultiSz->String = NULL;
  1060. }
  1061. else {
  1062. //
  1063. // Blow away the values. If there is failure, RestoreDeviceFilters
  1064. // will set the values back. If this functions fails, there is
  1065. // not much we can do!
  1066. //
  1067. SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
  1068. DeviceInfoData,
  1069. Property,
  1070. NULL,
  1071. 0);
  1072. }
  1073. }
  1074. }
  1075. }
  1076. void
  1077. GetDeviceFilters(
  1078. IN HDEVINFO DeviceInfoSet,
  1079. IN PSP_DEVINFO_DATA DeviceInfoData,
  1080. OUT PFILTERS Filters
  1081. )
  1082. {
  1083. GetFilterInfo(DeviceInfoSet, DeviceInfoData, SPDRP_LOWERFILTERS, &Filters->Lower);
  1084. GetFilterInfo(DeviceInfoSet, DeviceInfoData, SPDRP_UPPERFILTERS, &Filters->Upper);
  1085. }
  1086. void
  1087. FreeDeviceFilters(
  1088. OUT PFILTERS Filters
  1089. )
  1090. {
  1091. if (Filters->Lower.String) {
  1092. LocalFree(Filters->Lower.String);
  1093. ZeroMemory(&Filters->Lower, sizeof(MULTI_SZ));
  1094. }
  1095. if (Filters->Upper.String) {
  1096. LocalFree(Filters->Upper.String);
  1097. ZeroMemory(&Filters->Upper, sizeof(MULTI_SZ));
  1098. }
  1099. }
  1100. void
  1101. RestoreDeviceFilters(
  1102. IN HDEVINFO DeviceInfoSet,
  1103. IN PSP_DEVINFO_DATA DeviceInfoData,
  1104. OUT PFILTERS Filters
  1105. )
  1106. {
  1107. if (Filters->Lower.String) {
  1108. SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
  1109. DeviceInfoData,
  1110. SPDRP_LOWERFILTERS,
  1111. (CONST PBYTE) Filters->Lower.String,
  1112. Filters->Lower.Size);
  1113. }
  1114. if (Filters->Upper.String) {
  1115. SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
  1116. DeviceInfoData,
  1117. SPDRP_UPPERFILTERS,
  1118. (CONST PBYTE) Filters->Upper.String,
  1119. Filters->Upper.Size);
  1120. }
  1121. FreeDeviceFilters(Filters);
  1122. }
  1123. #if 0
  1124. VOID
  1125. EnableMultiplePorts(TCHAR *szPath)
  1126. {
  1127. TCHAR szConnectMultiple[] = TEXT("ConnectMultiplePorts"),
  1128. szConnectUpgraded[] = TEXT("ConnectMultiplePortsUpgraded");
  1129. DWORD dwConnectMultiple, dwConnectUpgraded, dwSize, dwType;
  1130. HKEY hKey;
  1131. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1132. szPath,
  1133. 0,
  1134. KEY_ALL_ACCESS,
  1135. &hKey) != ERROR_SUCCESS) {
  1136. return;
  1137. }
  1138. dwSize = sizeof(DWORD);
  1139. dwConnectUpgraded = 0;
  1140. if (RegQueryValueEx(hKey,
  1141. szConnectUpgraded,
  1142. 0,
  1143. &dwType,
  1144. (PBYTE) &dwConnectUpgraded,
  1145. &dwSize) == ERROR_SUCCESS &&
  1146. dwConnectUpgraded != 0) {
  1147. //
  1148. // We have munged with the value already, do nothing...
  1149. //;
  1150. }
  1151. else {
  1152. //
  1153. // 1 means use the grandmaster, 0 is use the device interface (no GM)
  1154. //
  1155. dwConnectMultiple = 0x0;
  1156. dwSize = sizeof(DWORD);
  1157. if (RegSetValueEx(hKey,
  1158. szConnectMultiple,
  1159. 0,
  1160. REG_DWORD,
  1161. (CONST PBYTE) &dwConnectMultiple,
  1162. dwSize) == ERROR_SUCCESS) {
  1163. //
  1164. // Mark the fact that we changed the value so we don't do it again
  1165. // if the user manually changes it back
  1166. //
  1167. dwSize = sizeof(DWORD);
  1168. dwConnectUpgraded = 1;
  1169. RegSetValueEx(hKey,
  1170. szConnectUpgraded,
  1171. 0,
  1172. REG_DWORD,
  1173. (CONST PBYTE) &dwConnectUpgraded,
  1174. dwSize);
  1175. }
  1176. }
  1177. RegCloseKey(hKey);
  1178. }
  1179. #endif
  1180. DWORD
  1181. MouseClassInstaller(
  1182. IN DI_FUNCTION InstallFunction,
  1183. IN HDEVINFO DeviceInfoSet,
  1184. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  1185. )
  1186. /*++
  1187. Routine Description:
  1188. This routine acts as the class installer for Mouse devices. In general,
  1189. the default behavior is all that is required for mice. The exceptions are:
  1190. 1. For DIF_INSTALLDEVICE, we first check to see if this driver also controls
  1191. other devices that we should warn the user about (e.g., PS/2 mouse driver
  1192. also controls i8042 port). Unless the user cancels out at that point, we
  1193. then do the default behavior of calling SetupDiInstallDevice. Next, we
  1194. delete the FriendlyName property, then move the GroupOrderList tag to the
  1195. front of the list, to ensure that the driver controlling this device loads
  1196. before any other drivers in this load order group.
  1197. 2. For DIF_ALLOW_INSTALL, we make sure that the driver node selected by the
  1198. user has a service install section. If not, then we assume it's a
  1199. Win95-only INF, and return ERROR_NON_WINDOWS_NT_DRIVER.
  1200. Arguments:
  1201. InstallFunction - Specifies the device installer function code indicating
  1202. the action being performed.
  1203. DeviceInfoSet - Supplies a handle to the device information set being
  1204. acted upon by this install action.
  1205. DeviceInfoData - Optionally, supplies the address of a device information
  1206. element being acted upon by this install action.
  1207. Return Value:
  1208. If this function successfully completed the requested action, the return
  1209. value is NO_ERROR.
  1210. If the default behavior is to be performed for the requested action, the
  1211. return value is ERROR_DI_DO_DEFAULT.
  1212. If an error occurred while attempting to perform the requested action, a
  1213. Win32 error code is returned.
  1214. --*/
  1215. {
  1216. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  1217. DWORD Err;
  1218. TCHAR DeviceDescription[LINE_LEN];
  1219. DWORD DeviceDescriptionLen;
  1220. TCHAR NewServiceName[MAX_SERVICE_NAME_LEN], OldServiceName[MAX_SERVICE_NAME_LEN];
  1221. BOOL IsKbdDriver, IsOnlyKbdDriver;
  1222. ULONG DevsControlled;
  1223. FILTERS filters;
  1224. ULONG DevStatus, DevProblem;
  1225. CONFIGRET Result;
  1226. BOOLEAN bDisableService;
  1227. switch(InstallFunction) {
  1228. case DIF_SELECTBESTCOMPATDRV:
  1229. //
  1230. // First, retrieve the device install parameters to see whether or not this is a
  1231. // silent install. If so, then we don't prompt the user during DIF_ALLOW_INSTALL.
  1232. //
  1233. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  1234. DeviceInstallParams.ClassInstallReserved = (ULONG_PTR)NULL;
  1235. if(SetupDiGetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams)) {
  1236. DeviceInstallParams.ClassInstallReserved = (ULONG_PTR)DeviceInstallParams.Flags;
  1237. SetupDiSetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams);
  1238. }
  1239. return ConfirmWHQLInputRequirements(DeviceInfoSet,
  1240. DeviceInfoData,
  1241. szNativeMouseServices,
  1242. szNativeMouseInf,
  1243. InstallFunction);
  1244. case DIF_ALLOW_INSTALL :
  1245. //
  1246. // Check to make sure the selected driver node supports NT.
  1247. //
  1248. Err = ConfirmWHQLInputRequirements(DeviceInfoSet,
  1249. DeviceInfoData,
  1250. szNativeMouseServices,
  1251. szNativeMouseInf,
  1252. InstallFunction);
  1253. if (Err == ERROR_DI_DO_DEFAULT || Err == ERROR_SUCCESS) {
  1254. if (DriverNodeSupportsNT(DeviceInfoSet, DeviceInfoData)) {
  1255. Err = NO_ERROR;
  1256. if (UserBalksAtSharedDrvMsg(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams)) {
  1257. Err = ERROR_DI_DONT_INSTALL;
  1258. }
  1259. }
  1260. else {
  1261. Err = ERROR_NON_WINDOWS_NT_DRIVER;
  1262. }
  1263. }
  1264. return Err;
  1265. case DIF_INSTALLDEVICE :
  1266. //
  1267. // Retrieve and cache the name of the service that's controlling this device.
  1268. //
  1269. if(!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  1270. DeviceInfoData,
  1271. SPDRP_SERVICE,
  1272. NULL,
  1273. (PBYTE)OldServiceName,
  1274. sizeof(OldServiceName),
  1275. NULL)) {
  1276. //
  1277. // We could not determine the old service - assume it is a null driver
  1278. //
  1279. OldServiceName[0] = (TCHAR) 0;
  1280. }
  1281. //
  1282. // Retrieve the status of this device instance.
  1283. //
  1284. Result = CM_Get_DevNode_Status(&DevStatus,
  1285. &DevProblem,
  1286. DeviceInfoData->DevInst,
  1287. 0);
  1288. if ((Result == CR_SUCCESS) &&
  1289. (DevStatus & DN_HAS_PROBLEM) &&
  1290. (DevProblem == CM_PROB_DISABLED_SERVICE)) {
  1291. InputClassLogError(LogSevInformation, TEXT("Mouse service is disabled, so will be disabling."));
  1292. bDisableService = TRUE;
  1293. }
  1294. else {
  1295. bDisableService = FALSE;
  1296. }
  1297. //
  1298. // Before we do anything, migrate the values from the services key
  1299. // up to the devnode
  1300. //
  1301. MigrateToDevnode(DeviceInfoSet, DeviceInfoData);
  1302. GetDeviceFilters(DeviceInfoSet, DeviceInfoData, &filters);
  1303. //
  1304. // We first want to perform the default behavior of calling
  1305. // SetupDiInstallDevice.
  1306. //
  1307. if(SetupDiInstallDevice(DeviceInfoSet, DeviceInfoData)) {
  1308. //
  1309. // Retrieve the name of the service which will now control the device
  1310. //
  1311. if(!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  1312. DeviceInfoData,
  1313. SPDRP_SERVICE,
  1314. NULL,
  1315. (PBYTE)NewServiceName,
  1316. sizeof(NewServiceName),
  1317. NULL)) {
  1318. InputClassLogError(LogSevInformation, TEXT("Couldn't get service name."));
  1319. //
  1320. // We must have the name of this service - fail if we can't find it
  1321. //
  1322. return GetLastError();
  1323. }
  1324. FixUpPS2Mouse(DeviceInfoSet, DeviceInfoData, NewServiceName);
  1325. //
  1326. // Only consider disabling the service if it has changed and we know the old service name
  1327. //
  1328. if (lstrcmpi(OldServiceName, NewServiceName) && OldServiceName[0] != (TCHAR)0) {
  1329. if ((Err = IsKeyboardDriver(OldServiceName, &IsKbdDriver)) != NO_ERROR) {
  1330. InputClassLogError(LogSevInformation, TEXT("Couldn't tell if keyboard or not."));
  1331. RestoreDeviceFilters(DeviceInfoSet, DeviceInfoData, &filters);
  1332. return Err;
  1333. }
  1334. if ((DevsControlled = CountDevicesControlled(OldServiceName)) != -1) {
  1335. // Disable the old driver service if:
  1336. // - it controls a keyboard, and a total of <= 2 devices (ie kbd & mouse) and it is not the
  1337. // only keyboard driver
  1338. // - it is just a mouse driver controling one device (it the mouse) and
  1339. // doesn't dynamically load
  1340. if (IsKbdDriver) {
  1341. InputClassLogError(LogSevInformation, TEXT("This is a keyboard driver."));
  1342. if((Err = IsOnlyKeyboardDriver(OldServiceName,&IsOnlyKbdDriver)) != NO_ERROR) {
  1343. InputClassLogError(LogSevInformation, TEXT("Couldn't tell if this is only keyboard."));
  1344. RestoreDeviceFilters(DeviceInfoSet, DeviceInfoData, &filters);
  1345. return Err;
  1346. }
  1347. if (DevsControlled <= 2 && !IsOnlyKbdDriver) {
  1348. InputClassLogError(LogSevInformation, TEXT("Not the only keyboard. Disabling."));
  1349. DisableService(OldServiceName);
  1350. }
  1351. } else {
  1352. if(DevsControlled == 1 &&
  1353. GetServiceStartType(OldServiceName) != SERVICE_DEMAND_START) {
  1354. InputClassLogError(LogSevInformation, TEXT("Only controls one mouse device and not demand start."));
  1355. DisableService(OldServiceName);
  1356. }
  1357. }
  1358. }
  1359. //
  1360. // If the driver service has changed we need to move the tag for this driver to the front
  1361. // of its group order list.
  1362. //
  1363. DrvTagToFrontOfGroupOrderList(DeviceInfoSet, DeviceInfoData);
  1364. }
  1365. Err = NO_ERROR;
  1366. //
  1367. // We may have previously had an 'unknown' driver controlling
  1368. // this device, with a FriendlyName generated by the user-mode
  1369. // PnP Manager. Delete this FriendlyName, since it's no longer
  1370. // applicable (the DeviceDescription will be used from now on
  1371. // in referring to this device).
  1372. //
  1373. SetupDiSetDeviceRegistryProperty(DeviceInfoSet, DeviceInfoData, SPDRP_FRIENDLYNAME, NULL, 0);
  1374. //
  1375. // Only disable the PS2 driver, all the other OEM driver replacements
  1376. // will not work becuase of PNP. This is especially true for
  1377. // serial mice.
  1378. //
  1379. if (bDisableService &&
  1380. lstrcmpi(NewServiceName, szPS2Driver) == 0) {
  1381. InputClassLogError(LogSevInformation, TEXT("Disabling mouse."));
  1382. Err = DisableService(NewServiceName);
  1383. }
  1384. #if 0
  1385. //
  1386. // We now change the value to 0 regardless if the user changed it
  1387. // to 1 after we installed previously
  1388. //
  1389. EnableMultiplePorts(szMouclassParameters);
  1390. #endif
  1391. FreeDeviceFilters(&filters);
  1392. return NO_ERROR;
  1393. } else {
  1394. Err = GetLastError();
  1395. InputClassLogError(LogSevInformation, TEXT("SetupDiInstallDevice failed with status %x."), Err);
  1396. if(Err != ERROR_CANCELLED) {
  1397. //
  1398. // If the error was for anything other than a user cancel, then bail now.
  1399. //
  1400. return Err;
  1401. }
  1402. //
  1403. // Is there a driver installed for this device? If so, then the user started to
  1404. // change the driver, then changed their mind. We don't want to do anything special
  1405. // in this case.
  1406. //
  1407. if(SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  1408. DeviceInfoData,
  1409. SPDRP_SERVICE,
  1410. NULL,
  1411. (PBYTE)DeviceDescription,
  1412. sizeof(DeviceDescription),
  1413. NULL))
  1414. {
  1415. return ERROR_CANCELLED;
  1416. }
  1417. //
  1418. // The user cancelled out of the installation. There are two scenarios where
  1419. // this could happen:
  1420. //
  1421. // 1. There really was a mouse to be installed, but the user changed their
  1422. // mind, didn't have the source media, etc.
  1423. // 2. There wasn't really a mouse. This happens with certain modems that
  1424. // fool ntdetect into thinking that they're really mice. The poor user
  1425. // doesn't get a chance to nip this in the bud earlier, because umpnpmgr
  1426. // generates an ID that yields a rank-0 match.
  1427. //
  1428. // Scenario (2) is particularly annoying, because the user will get the popup
  1429. // again and again, until they finally agree to install the sermouse driver (even
  1430. // though they don't have a serial mouse).
  1431. //
  1432. // To work around this problem, we special case the user-cancel scenario by going
  1433. // ahead and installing the NULL driver for this device. This will keep the user
  1434. // from getting any more popups. However, it doesn't mess up the user who cancelled
  1435. // because of scenario (1). That's because this device is still of class "Mouse",
  1436. // and thus will show up in the mouse cpl. We write out a friendly name for it that
  1437. // has the text " (no driver)" at the end, to indicate that this device currently has
  1438. // the NULL driver installed. That way, if the user really experienced scenario (1),
  1439. // they can later go to the Mouse cpl, select the no-driver device, and click the
  1440. // "Change" button to install the correct driver for it.
  1441. //
  1442. SetupDiSetSelectedDriver(DeviceInfoSet, DeviceInfoData, NULL);
  1443. SetupDiInstallDevice(DeviceInfoSet, DeviceInfoData);
  1444. if(SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  1445. DeviceInfoData,
  1446. SPDRP_DEVICEDESC,
  1447. NULL,
  1448. (PBYTE)DeviceDescription,
  1449. sizeof(DeviceDescription),
  1450. &DeviceDescriptionLen))
  1451. {
  1452. //
  1453. // Need length in characters, not bytes.
  1454. //
  1455. DeviceDescriptionLen /= sizeof(TCHAR);
  1456. //
  1457. // Don't count trailing NULL.
  1458. //
  1459. DeviceDescriptionLen--;
  1460. } else {
  1461. //
  1462. // We couldn't get the device description--fall back to our default description.
  1463. //
  1464. DeviceDescriptionLen = LoadString(MyModuleHandle,
  1465. IDS_DEVNAME_UNK,
  1466. DeviceDescription,
  1467. SIZECHARS(DeviceDescription)
  1468. );
  1469. }
  1470. //
  1471. // Now, append our " (no driver)" text.
  1472. //
  1473. LoadString(MyModuleHandle,
  1474. IDS_NODRIVER,
  1475. &(DeviceDescription[DeviceDescriptionLen]),
  1476. SIZECHARS(DeviceDescription) - DeviceDescriptionLen
  1477. );
  1478. //
  1479. // And, finally, set the friendly name for this device to be the description we
  1480. // just generated.
  1481. //
  1482. SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
  1483. DeviceInfoData,
  1484. SPDRP_FRIENDLYNAME,
  1485. (PBYTE)DeviceDescription,
  1486. (lstrlen(DeviceDescription) + 1) * sizeof(TCHAR)
  1487. );
  1488. RestoreDeviceFilters(DeviceInfoSet, DeviceInfoData, &filters);
  1489. return ERROR_CANCELLED;
  1490. }
  1491. case DIF_ADDPROPERTYPAGE_ADVANCED:
  1492. if (DeviceInfoData) {
  1493. //
  1494. // Retrieve the status of this device instance.
  1495. //
  1496. Result = CM_Get_DevNode_Status(&DevStatus,
  1497. &DevProblem,
  1498. DeviceInfoData->DevInst,
  1499. 0);
  1500. if ((Result == CR_SUCCESS) &&
  1501. (DevStatus & DN_HAS_PROBLEM) &&
  1502. (DevProblem == CM_PROB_DISABLED_SERVICE)) {
  1503. //
  1504. // If the controlling service has been disabled, this device
  1505. // is most likely under the control of a legacy driver. We
  1506. // should not let device manager display the standard
  1507. // driver, resource, or power property pages by claiming to
  1508. // have added them here.
  1509. //
  1510. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  1511. SetupDiGetDeviceInstallParams(DeviceInfoSet,
  1512. DeviceInfoData,
  1513. &DeviceInstallParams);
  1514. DeviceInstallParams.Flags |= (DI_DRIVERPAGE_ADDED | DI_RESOURCEPAGE_ADDED);
  1515. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_POWERPAGE_ADDED;
  1516. SetupDiSetDeviceInstallParams(DeviceInfoSet,
  1517. DeviceInfoData,
  1518. &DeviceInstallParams);
  1519. return NO_ERROR;
  1520. }
  1521. }
  1522. return ERROR_DI_DO_DEFAULT;
  1523. default :
  1524. //
  1525. // Just do the default action.
  1526. //
  1527. return ERROR_DI_DO_DEFAULT;
  1528. }
  1529. }
  1530. typedef struct _VALUE_INFORMATION {
  1531. DWORD dwSize;
  1532. DWORD dwType;
  1533. PVOID pData;
  1534. PTCHAR szName;
  1535. } VALUE_INFORMATION, *PVALUE_INFORMATION;
  1536. BOOL
  1537. KeyboardClassInstallDevice(
  1538. IN HDEVINFO DeviceInfoSet,
  1539. IN PSP_DEVINFO_DATA DeviceInfoData
  1540. )
  1541. {
  1542. PVALUE_INFORMATION values = NULL, currentValue;
  1543. ULONG numValues = 0;
  1544. HKEY hSource = (HKEY) INVALID_HANDLE_VALUE;
  1545. SP_DEVINSTALL_PARAMS dip;
  1546. SP_DRVINFO_DETAIL_DATA didd;
  1547. SP_DRVINFO_DATA did;
  1548. HINF hInf = INVALID_HANDLE_VALUE;
  1549. INFCONTEXT infContext;
  1550. DWORD dwSize;
  1551. TCHAR szSectionName[LINE_LEN];
  1552. PTCHAR szService = NULL, szServicePath = NULL,
  1553. szValueNames = NULL, szCurrentName = NULL;
  1554. BOOL success = FALSE;
  1555. TCHAR szRegServices[] = TEXT("System\\CurrentControlSet\\Services\\");
  1556. TCHAR szParameters[] = TEXT("\\Parameters");
  1557. TCHAR szMaintain[] = TEXT(".KeepValues");
  1558. BOOL installedDevice = FALSE;
  1559. FILTERS filters;
  1560. //
  1561. // Only save the values if we are in gui mode setup
  1562. //
  1563. if (!pInGUISetup(DeviceInfoSet, DeviceInfoData)) {
  1564. goto cleanup;
  1565. }
  1566. //
  1567. // Retrieve information about the driver node selected for this device.
  1568. //
  1569. did.cbSize = sizeof(SP_DRVINFO_DATA);
  1570. if(!SetupDiGetSelectedDriver(DeviceInfoSet, DeviceInfoData, &did)) {
  1571. InputClassLogError(LogSevInformation, TEXT("SetupDiGetSelectedDriver failed."));
  1572. goto cleanup;
  1573. }
  1574. didd.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  1575. if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
  1576. DeviceInfoData,
  1577. &did,
  1578. &didd,
  1579. sizeof(didd),
  1580. NULL)
  1581. && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
  1582. InputClassLogError(LogSevInformation, TEXT("Couldn't get driver details."));
  1583. //
  1584. // For some reason we couldn't get detail data--this should never happen.
  1585. //
  1586. goto cleanup;
  1587. }
  1588. //
  1589. // Open the INF that installs this driver node
  1590. //
  1591. hInf = SetupOpenInfFile(didd.InfFileName,
  1592. NULL,
  1593. INF_STYLE_WIN4,
  1594. NULL
  1595. );
  1596. if (hInf == INVALID_HANDLE_VALUE) {
  1597. //
  1598. // For some reason we couldn't open the INF--this should never happen.
  1599. //
  1600. goto cleanup;
  1601. }
  1602. SetupDiGetActualSectionToInstall(hInf,
  1603. didd.SectionName,
  1604. szSectionName,
  1605. sizeof(szSectionName) / sizeof(TCHAR),
  1606. NULL,
  1607. NULL
  1608. );
  1609. wcscat(szSectionName, szMaintain);
  1610. if (!SetupFindFirstLine(hInf,
  1611. szSectionName,
  1612. NULL,
  1613. &infContext)) {
  1614. //
  1615. // No such section, just install the device and return
  1616. //
  1617. goto cleanup;
  1618. }
  1619. dwSize = 0;
  1620. if (SetupGetStringField(&infContext, 0, NULL, 0, &dwSize)) {
  1621. //
  1622. // Increment the count to hold the null and alloc. The count returned
  1623. // is the number of characters in the strings, NOT the number of bytes
  1624. // needed.
  1625. //
  1626. dwSize++;
  1627. szService = (PTCHAR) LocalAlloc(LPTR, dwSize * sizeof(TCHAR));
  1628. if (!szService ||
  1629. !SetupGetStringField(&infContext, 0, szService, dwSize, &dwSize)) {
  1630. goto cleanup;
  1631. }
  1632. }
  1633. else {
  1634. goto cleanup;
  1635. }
  1636. dwSize = wcslen(szRegServices)+wcslen(szService)+wcslen(szParameters)+1;
  1637. dwSize *= sizeof(TCHAR);
  1638. szServicePath = (PTCHAR) LocalAlloc(LPTR, dwSize);
  1639. if (!szServicePath) {
  1640. goto cleanup;
  1641. }
  1642. wcscpy(szServicePath, szRegServices);
  1643. wcscat(szServicePath, szService);
  1644. wcscat(szServicePath, szParameters);
  1645. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1646. szServicePath,
  1647. 0,
  1648. KEY_ALL_ACCESS,
  1649. &hSource) != ERROR_SUCCESS) {
  1650. goto cleanup;
  1651. }
  1652. dwSize = 0;
  1653. if (SetupGetMultiSzField(&infContext, 1, NULL, 0, &dwSize)) {
  1654. //
  1655. // Increment the count to hold the null and alloc. The count returned
  1656. // is the number of characters in the strings, NOT the number of bytes
  1657. // needed.
  1658. //
  1659. dwSize++;
  1660. szValueNames = (PTCHAR) LocalAlloc(LPTR, dwSize * sizeof(TCHAR));
  1661. if (!szValueNames ||
  1662. !SetupGetMultiSzField(&infContext, 1, szValueNames, dwSize, &dwSize)) {
  1663. goto cleanup;
  1664. }
  1665. }
  1666. else {
  1667. goto cleanup;
  1668. }
  1669. numValues = SetupGetFieldCount(&infContext);
  1670. values = (PVALUE_INFORMATION)
  1671. LocalAlloc(LPTR, (numValues + 1) * sizeof(VALUE_INFORMATION));
  1672. if (!values) {
  1673. goto cleanup;
  1674. }
  1675. currentValue = values;
  1676. for (szCurrentName = szValueNames;
  1677. *szCurrentName;
  1678. szCurrentName += wcslen(szCurrentName) + 1) {
  1679. if (RegQueryValueEx(hSource,
  1680. szCurrentName,
  1681. 0,
  1682. &currentValue->dwType,
  1683. (PBYTE) NULL,
  1684. &currentValue->dwSize) == ERROR_SUCCESS) {
  1685. currentValue->szName = szCurrentName;
  1686. currentValue->pData = LocalAlloc(LPTR, currentValue->dwSize);
  1687. if (!currentValue->pData) {
  1688. ZeroMemory(currentValue, sizeof(VALUE_INFORMATION));
  1689. continue;
  1690. }
  1691. if (RegQueryValueEx(hSource,
  1692. currentValue->szName,
  1693. 0,
  1694. &currentValue->dwType,
  1695. (PBYTE) currentValue->pData,
  1696. &currentValue->dwSize) == ERROR_SUCCESS) {
  1697. currentValue++;
  1698. }
  1699. else {
  1700. ZeroMemory(currentValue, sizeof(VALUE_INFORMATION));
  1701. }
  1702. }
  1703. }
  1704. GetDeviceFilters(DeviceInfoSet, DeviceInfoData, &filters);
  1705. installedDevice = TRUE;
  1706. success = SetupDiInstallDevice(DeviceInfoSet, DeviceInfoData);
  1707. for (currentValue = values; ; currentValue++) {
  1708. if (currentValue->pData) {
  1709. if (success) {
  1710. RegSetValueEx(hSource,
  1711. currentValue->szName,
  1712. 0,
  1713. currentValue->dwType,
  1714. (PBYTE) currentValue->pData,
  1715. currentValue->dwSize);
  1716. }
  1717. LocalFree(currentValue->pData);
  1718. }
  1719. else {
  1720. //
  1721. // if currentValue->pData is blank, no other entries exist
  1722. //
  1723. break;
  1724. }
  1725. }
  1726. LocalFree(values);
  1727. cleanup:
  1728. //
  1729. // Clean up and leave
  1730. //
  1731. if (hInf != (HKEY) INVALID_HANDLE_VALUE) {
  1732. SetupCloseInfFile(hInf);
  1733. }
  1734. if (hSource != (HKEY) INVALID_HANDLE_VALUE) {
  1735. RegCloseKey(hSource);
  1736. }
  1737. if (szService) {
  1738. LocalFree(szService);
  1739. }
  1740. if (szServicePath) {
  1741. LocalFree(szServicePath);
  1742. }
  1743. if (szValueNames) {
  1744. LocalFree(szValueNames);
  1745. }
  1746. if (!installedDevice) {
  1747. GetDeviceFilters(DeviceInfoSet, DeviceInfoData, &filters);
  1748. success = SetupDiInstallDevice(DeviceInfoSet, DeviceInfoData);
  1749. }
  1750. if (success) {
  1751. FreeDeviceFilters(&filters);
  1752. }
  1753. else {
  1754. RestoreDeviceFilters(DeviceInfoSet, DeviceInfoData, &filters);
  1755. }
  1756. return success;
  1757. }
  1758. TCHAR szKbdclassParameters[] = TEXT("System\\CurrentControlSet\\Services\\Kbdclass\\Parameters");
  1759. TCHAR szNativeKeyboardInf[] = TEXT("keyboard.inf");
  1760. TCHAR szNativeKeyboardServices[] =
  1761. TEXT("KBDCLASS\0")
  1762. TEXT("I8042PRT\0")
  1763. TEXT("KBDHID\0")
  1764. TEXT("\0");
  1765. DWORD
  1766. KeyboardClassInstaller(
  1767. IN DI_FUNCTION InstallFunction,
  1768. IN HDEVINFO DeviceInfoSet,
  1769. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  1770. )
  1771. /*++
  1772. Routine Description:
  1773. This routine acts as the class installer for Keyboard devices. In general,
  1774. the default behavior is all that is required for keyboards. The exceptions are:
  1775. 1. For DIF_INSTALLDEVICE, we first check to see if this driver also controls
  1776. other devices that we should warn the user about (e.g., i8042 keyboard driver
  1777. also controls PS/2 mouse port). Unless the user cancels out at that point, we
  1778. then do the default behavior of calling SetupDiInstallDevice. Next, we
  1779. delete the FriendlyName property, then move the GroupOrderList tag to the
  1780. front of the list, to ensure that the driver controlling this device loads
  1781. before any other drivers in this load order group.
  1782. 2. For DIF_ALLOW_INSTALL, we make sure that the driver node selected by the
  1783. user has a service install section. If not, then we assume it's a
  1784. Win95-only INF, and return ERROR_NON_WINDOWS_NT_DRIVER.
  1785. Arguments:
  1786. InstallFunction - Specifies the device installer function code indicating
  1787. the action being performed.
  1788. DeviceInfoSet - Supplies a handle to the device information set being
  1789. acted upon by this install action.
  1790. DeviceInfoData - Optionally, supplies the address of a device information
  1791. element being acted upon by this install action.
  1792. Return Value:
  1793. If this function successfully completed the requested action, the return
  1794. value is NO_ERROR.
  1795. If the default behavior is to be performed for the requested action, the
  1796. return value is ERROR_DI_DO_DEFAULT.
  1797. If an error occurred while attempting to perform the requested action, a
  1798. Win32 error code is returned.
  1799. --*/
  1800. {
  1801. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  1802. TCHAR OldServiceName[MAX_SERVICE_NAME_LEN], NewServiceName[MAX_SERVICE_NAME_LEN];
  1803. DWORD Err;
  1804. ULONG DevStatus, DevProblem;
  1805. CONFIGRET Result;
  1806. BOOLEAN bDisableService;
  1807. switch(InstallFunction) {
  1808. case DIF_SELECTBESTCOMPATDRV:
  1809. //
  1810. // First, retrieve the device install parameters to see whether or not this is a
  1811. // silent install. If so, then we don't prompt the user during DIF_ALLOW_INSTALL.
  1812. //
  1813. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  1814. DeviceInstallParams.ClassInstallReserved = (ULONG_PTR)NULL;
  1815. if(SetupDiGetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams)) {
  1816. DeviceInstallParams.ClassInstallReserved = (ULONG_PTR)DeviceInstallParams.Flags;
  1817. SetupDiSetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams);
  1818. }
  1819. return ConfirmWHQLInputRequirements(DeviceInfoSet,
  1820. DeviceInfoData,
  1821. szNativeKeyboardServices,
  1822. szNativeKeyboardInf,
  1823. InstallFunction);
  1824. case DIF_ALLOW_INSTALL :
  1825. //
  1826. // Check to make sure the selected driver node supports NT.
  1827. //
  1828. Err = ConfirmWHQLInputRequirements(DeviceInfoSet,
  1829. DeviceInfoData,
  1830. szNativeKeyboardServices,
  1831. szNativeKeyboardInf,
  1832. InstallFunction);
  1833. if (Err == ERROR_DI_DO_DEFAULT || Err == ERROR_SUCCESS) {
  1834. if (DriverNodeSupportsNT(DeviceInfoSet, DeviceInfoData)) {
  1835. Err = NO_ERROR;
  1836. if (UserBalksAtSharedDrvMsg(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams)) {
  1837. Err = ERROR_DI_DONT_INSTALL;
  1838. }
  1839. }
  1840. else {
  1841. Err = ERROR_NON_WINDOWS_NT_DRIVER;
  1842. }
  1843. }
  1844. return Err;
  1845. case DIF_INSTALLDEVICE :
  1846. //
  1847. // Retrieve and cache the name of the service that's controlling this device.
  1848. //
  1849. if(!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  1850. DeviceInfoData,
  1851. SPDRP_SERVICE,
  1852. NULL,
  1853. (PBYTE)OldServiceName,
  1854. sizeof(OldServiceName),
  1855. NULL)) {
  1856. //
  1857. // We could not determine the old service - assume it is a null driver
  1858. //
  1859. OldServiceName[0] = (TCHAR) 0;
  1860. }
  1861. //
  1862. // Before we do anything, migrate the values from the services key
  1863. // up to the devnode
  1864. //
  1865. MigrateToDevnode(DeviceInfoSet, DeviceInfoData);
  1866. //
  1867. // Retrieve the status of this device instance.
  1868. //
  1869. Result = CM_Get_DevNode_Status(&DevStatus,
  1870. &DevProblem,
  1871. DeviceInfoData->DevInst,
  1872. 0);
  1873. if ((Result == CR_SUCCESS) &&
  1874. (DevStatus & DN_HAS_PROBLEM) &&
  1875. (DevProblem == CM_PROB_DISABLED_SERVICE)) {
  1876. InputClassLogError(LogSevInformation, TEXT("Keyboard is disabled, so will disable."));
  1877. bDisableService = TRUE;
  1878. }
  1879. else {
  1880. bDisableService = FALSE;
  1881. }
  1882. //
  1883. // Perform the default behavior of calling SetupDiInstallDevice.
  1884. //
  1885. if(KeyboardClassInstallDevice(DeviceInfoSet, DeviceInfoData)) {
  1886. //
  1887. // Retrieve the name of the service which will now control the device
  1888. //
  1889. if(!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  1890. DeviceInfoData,
  1891. SPDRP_SERVICE,
  1892. NULL,
  1893. (PBYTE)NewServiceName,
  1894. sizeof(NewServiceName),
  1895. NULL)) {
  1896. return GetLastError();
  1897. }
  1898. //
  1899. // Only consider disabling the service if it has changed and we know the old service name
  1900. //
  1901. if(lstrcmpi(OldServiceName, NewServiceName) && OldServiceName[0] != (TCHAR)0) {
  1902. //
  1903. // Disable the old service that was controlling the device
  1904. //
  1905. InputClassLogError(LogSevInformation, TEXT("Disabling old service to start new one."));
  1906. if((Err = DisableService(OldServiceName)) != NO_ERROR) {
  1907. return Err;
  1908. }
  1909. //
  1910. // If the driver service has changed we need to move the tag for this driver to the front
  1911. // of its group order list.
  1912. //
  1913. DrvTagToFrontOfGroupOrderList(DeviceInfoSet, DeviceInfoData);
  1914. }
  1915. Err = NO_ERROR;
  1916. //
  1917. // We may have previously had an 'unknown' driver controlling
  1918. // this device, with a FriendlyName generated by the user-mode
  1919. // PnP Manager. Delete this FriendlyName, since it's no longer
  1920. // applicable (the DeviceDescription will be used from now on
  1921. // in referring to this device).
  1922. //
  1923. SetupDiSetDeviceRegistryProperty(DeviceInfoSet, DeviceInfoData, SPDRP_FRIENDLYNAME, NULL, 0);
  1924. if (bDisableService &&
  1925. lstrcmpi(NewServiceName, szPS2Driver) == 0) {
  1926. InputClassLogError(LogSevInformation, TEXT("Disabling PS2 keyboard."));
  1927. Err = DisableService(NewServiceName);
  1928. }
  1929. #if 0
  1930. //
  1931. // We now change the value to 0 regardless if the user changed it
  1932. // to 1 after we installed previously
  1933. //
  1934. EnableMultiplePorts(szKbdclassParameters);
  1935. #endif
  1936. return Err;
  1937. } else {
  1938. InputClassLogError(LogSevInformation, TEXT("KeyboardClassInstallDevice failed."));
  1939. return GetLastError();
  1940. }
  1941. case DIF_ADDPROPERTYPAGE_ADVANCED:
  1942. if (DeviceInfoData) {
  1943. //
  1944. // Retrieve the status of this device instance.
  1945. //
  1946. Result = CM_Get_DevNode_Status(&DevStatus,
  1947. &DevProblem,
  1948. DeviceInfoData->DevInst,
  1949. 0);
  1950. if ((Result == CR_SUCCESS) &&
  1951. (DevStatus & DN_HAS_PROBLEM) &&
  1952. (DevProblem == CM_PROB_DISABLED_SERVICE)) {
  1953. //
  1954. // If the controlling service has been disabled, this device
  1955. // is most likely under the control of a legacy driver. We
  1956. // should not let device manager display the standard
  1957. // driver, resource, or power property pages by claiming to
  1958. // have added them here.
  1959. //
  1960. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  1961. SetupDiGetDeviceInstallParams(DeviceInfoSet,
  1962. DeviceInfoData,
  1963. &DeviceInstallParams);
  1964. DeviceInstallParams.Flags |= (DI_DRIVERPAGE_ADDED | DI_RESOURCEPAGE_ADDED);
  1965. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_POWERPAGE_ADDED;
  1966. SetupDiSetDeviceInstallParams(DeviceInfoSet,
  1967. DeviceInfoData,
  1968. &DeviceInstallParams);
  1969. return NO_ERROR;
  1970. }
  1971. }
  1972. return ERROR_DI_DO_DEFAULT;
  1973. default :
  1974. //
  1975. // Just do the default action.
  1976. //
  1977. return ERROR_DI_DO_DEFAULT;
  1978. }
  1979. }
  1980. DWORD
  1981. DrvTagToFrontOfGroupOrderList(
  1982. IN HDEVINFO DeviceInfoSet,
  1983. IN PSP_DEVINFO_DATA DeviceInfoData
  1984. )
  1985. /*++
  1986. Routine Description:
  1987. This routine moves the tag value for the specified device's driver to the
  1988. front of its corresponding GroupOrderList entry.
  1989. ********** We don't do the following any more *************************
  1990. It also marks the device's service with a PlugPlayServiceType value of
  1991. 0x2 (PlugPlayServicePeripheral), so that we won't attempt to generate a
  1992. legacy device instance for this service in the future.
  1993. ***********************************************************************
  1994. Arguments:
  1995. DeviceInfoSet - Supplies a handle to the device information set containing
  1996. the device whose driver is being modified.
  1997. DeviceInfoData - Supplies the address of a device information element whose
  1998. driver is being modified.
  1999. Return Value:
  2000. If the function is successful, the return value is NO_ERROR.
  2001. If the function fails, the return value is a Win32 error code.
  2002. --*/
  2003. {
  2004. TCHAR ServiceName[MAX_SERVICE_NAME_LEN];
  2005. SC_HANDLE SCMHandle, ServiceHandle;
  2006. DWORD Err;
  2007. LPQUERY_SERVICE_CONFIG ServiceConfig;
  2008. //
  2009. // Retrieve the name of the service that's controlling this device.
  2010. //
  2011. if(!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  2012. DeviceInfoData,
  2013. SPDRP_SERVICE,
  2014. NULL,
  2015. (PBYTE)ServiceName,
  2016. sizeof(ServiceName),
  2017. NULL)) {
  2018. return GetLastError();
  2019. }
  2020. //
  2021. // Now open this service, and call some private Setup API helper routines to
  2022. // retrieve the tag, and move it to the front of the GroupOrderList.
  2023. //
  2024. if(!(SCMHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
  2025. return GetLastError();
  2026. }
  2027. if(!(ServiceHandle = OpenService(SCMHandle, ServiceName, SERVICE_ALL_ACCESS))) {
  2028. Err = GetLastError();
  2029. goto clean0;
  2030. }
  2031. if((Err = pSetupRetrieveServiceConfig(ServiceHandle, &ServiceConfig)) != NO_ERROR) {
  2032. goto clean1;
  2033. }
  2034. //
  2035. // Only do this if this is a kernel or filesystem driver, and it's a member of
  2036. // a load group (with a tag assigned). This should always be the case for keyboard
  2037. // and mouse drivers, but this is just to be safe.
  2038. //
  2039. if(ServiceConfig->lpLoadOrderGroup && *(ServiceConfig->lpLoadOrderGroup) &&
  2040. (ServiceConfig->dwServiceType & (SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER))) {
  2041. //
  2042. // This driver meets all the criteria--it better have a tag!!!
  2043. //
  2044. MYASSERT(ServiceConfig->dwTagId);
  2045. //
  2046. // Move the tag to the front of the list.
  2047. //
  2048. Err = pSetupAddTagToGroupOrderListEntry(ServiceConfig->lpLoadOrderGroup,
  2049. ServiceConfig->dwTagId,
  2050. TRUE
  2051. );
  2052. }
  2053. MyFree(ServiceConfig);
  2054. clean1:
  2055. CloseServiceHandle(ServiceHandle);
  2056. clean0:
  2057. CloseServiceHandle(SCMHandle);
  2058. return Err;
  2059. }
  2060. BOOL
  2061. UserBalksAtSharedDrvMsg(
  2062. IN HDEVINFO DeviceInfoSet,
  2063. IN PSP_DEVINFO_DATA DeviceInfoData,
  2064. IN PSP_DEVINSTALL_PARAMS DeviceInstallParams
  2065. )
  2066. /*++
  2067. Routine Description:
  2068. This routine finds out if there are any other devices affected by the impending
  2069. device installation, and if so, warns the user about it (unless this is a quiet
  2070. installation).
  2071. Arguments:
  2072. DeviceInfoSet - Supplies a handle to the device information set containing
  2073. the device whose driver is being modified.
  2074. DeviceInfoData - Supplies the address of a device information element whose
  2075. driver is being modified.
  2076. DeviceInstallParams - Supplies the address of a device install parameters structure
  2077. to be used in this routine. Since callers of this routine always have this
  2078. structure 'laying around', they provide it to this routine to be used as a
  2079. workspace.
  2080. Return Value:
  2081. If the user decides not to go through with it, the return value is TRUE, otherwise
  2082. it is FALSE.
  2083. --*/
  2084. {
  2085. SP_DRVINFO_DATA DriverInfoData;
  2086. SP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
  2087. HINF hInf;
  2088. BOOL b, result;
  2089. INFCONTEXT InfContext;
  2090. PCTSTR SectionName, AffectedComponentsString;
  2091. PTSTR WarnMessage;
  2092. //
  2093. // First, retrieve the device install parameters to see whether or not this is a
  2094. // silent install. If so, then we don't prompt the user. We saved away these
  2095. // params during DIF_SELECTBESTCOMPATDRV, so check this first.
  2096. //
  2097. DeviceInstallParams->cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  2098. if(SetupDiGetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, DeviceInstallParams)) {
  2099. if((DeviceInstallParams->Flags & DI_QUIETINSTALL) ||
  2100. (DeviceInstallParams->ClassInstallReserved & DI_QUIETINSTALL)) {
  2101. InputClassLogError(LogSevInformation, TEXT("Quiet install requested."));
  2102. return FALSE;
  2103. }
  2104. } else {
  2105. //
  2106. // Couldn't retrieve the device install params--initialize the parent window handle
  2107. // to NULL, in case we need it later for the user prompt dialog.
  2108. //
  2109. DeviceInstallParams->hwndParent = NULL;
  2110. }
  2111. //
  2112. // Retrieve the currently-selected driver we're about to install.
  2113. //
  2114. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  2115. if(!SetupDiGetSelectedDriver(DeviceInfoSet,
  2116. DeviceInfoData,
  2117. &DriverInfoData)) {
  2118. return FALSE;
  2119. }
  2120. //
  2121. // Retrieve information about the INF install section for the selected driver.
  2122. //
  2123. DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  2124. if(!SetupDiGetDriverInfoDetail(DeviceInfoSet,
  2125. DeviceInfoData,
  2126. &DriverInfoData,
  2127. &DriverInfoDetailData,
  2128. sizeof(DriverInfoDetailData),
  2129. NULL)
  2130. && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
  2131. {
  2132. //
  2133. // Then we failed, and it wasn't simply because we didn't provide the extra
  2134. // space for hardware/compatible IDs.
  2135. //
  2136. return FALSE;
  2137. }
  2138. //
  2139. // Open the associated INF file.
  2140. //
  2141. if((hInf = SetupOpenInfFile(DriverInfoDetailData.InfFileName,
  2142. NULL,
  2143. INF_STYLE_WIN4,
  2144. NULL)) == INVALID_HANDLE_VALUE) {
  2145. return FALSE;
  2146. }
  2147. //
  2148. // Now look through the [ControlFlags] section at all 'SharedDriver' entries, to
  2149. // see if any of them reference an install section that matches what we're about
  2150. // to install.
  2151. //
  2152. for(b = SetupFindFirstLine(hInf, INFSTR_CONTROLFLAGS_SECTION, TEXT("SharedDriver"), &InfContext);
  2153. b;
  2154. b = SetupFindNextMatchLine(&InfContext, TEXT("SharedDriver"), &InfContext))
  2155. {
  2156. //
  2157. // The format of the line is SharedDriver=<InstallSection>,<AffectedComponentsString>
  2158. //
  2159. if((SectionName = pSetupGetField(&InfContext, 1)) &&
  2160. !lstrcmpi(SectionName, DriverInfoDetailData.SectionName)) {
  2161. //
  2162. // We found a match--now retrieve the string describing the other component(s) that
  2163. // are affected by this installation.
  2164. //
  2165. if(AffectedComponentsString = pSetupGetField(&InfContext, 2)) {
  2166. break;
  2167. }
  2168. }
  2169. }
  2170. if(!b) {
  2171. //
  2172. // Then we never found a match.
  2173. //
  2174. result = FALSE;
  2175. }
  2176. else {
  2177. //
  2178. // We need to popup a message box to the user--retrieve the parent window handle for this
  2179. // device information element.
  2180. //
  2181. result = (IDNO == MessageBoxFromMessage(DeviceInstallParams->hwndParent,
  2182. MSG_CONFIRM_SHAREDDRV_INSTALL,
  2183. NULL,
  2184. IDS_CONFIRM_DEVINSTALL,
  2185. MB_ICONWARNING | MB_YESNO,
  2186. AffectedComponentsString));
  2187. }
  2188. SetupCloseInfFile(hInf);
  2189. return result;
  2190. }
  2191. VOID
  2192. CopyFixedUpDeviceId(
  2193. OUT LPWSTR DestinationString,
  2194. IN LPCWSTR SourceString,
  2195. IN DWORD SourceStringLen
  2196. )
  2197. /*++
  2198. Routine Description:
  2199. This routine copies a device id, fixing it up as it does the copy.
  2200. 'Fixing up' means that the string is made upper-case, and that the
  2201. following character ranges are turned into underscores (_):
  2202. c <= 0x20 (' ')
  2203. c > 0x7F
  2204. c == 0x2C (',')
  2205. (NOTE: This algorithm is also implemented in the Config Manager APIs,
  2206. and must be kept in sync with that routine. To maintain device identifier
  2207. compatibility, these routines must work the same as Win95.)
  2208. Arguments:
  2209. DestinationString - Supplies a pointer to the destination string buffer
  2210. where the fixed-up device id is to be copied. This buffer must
  2211. be large enough to hold a copy of the source string (including
  2212. terminating NULL).
  2213. SourceString - Supplies a pointer to the (null-terminated) source
  2214. string to be fixed up.
  2215. SourceStringLen - Supplies the length, in characters, of the source
  2216. string (not including terminating NULL).
  2217. Return Value:
  2218. None. If an exception occurs during processing, the DestinationString will
  2219. be empty upon return.
  2220. --*/
  2221. {
  2222. PWCHAR p;
  2223. try {
  2224. CopyMemory(DestinationString,
  2225. SourceString,
  2226. (SourceStringLen + 1) * sizeof(TCHAR)
  2227. );
  2228. CharUpperBuff(DestinationString, SourceStringLen);
  2229. for(p = DestinationString; *p; p++) {
  2230. if((*p <= TEXT(' ')) || (*p > (WCHAR)0x7F) || (*p == TEXT(','))) {
  2231. *p = TEXT('_');
  2232. }
  2233. }
  2234. } except(EXCEPTION_EXECUTE_HANDLER) {
  2235. *DestinationString = TEXT('\0');
  2236. }
  2237. }
  2238. HANDLE
  2239. SpawnPnPInitialization(
  2240. VOID
  2241. )
  2242. /*++
  2243. Routine Description:
  2244. This routine spawns a PnP initialization thread that runs asynchronously to the rest of
  2245. the installation.
  2246. Arguments:
  2247. None.
  2248. Return Value:
  2249. If the thread was successfully created, the return value is a handle to the thread.
  2250. If a failure occurred, the return value is NULL, and a (non-fatal) error is logged.
  2251. --*/
  2252. {
  2253. HANDLE h;
  2254. DWORD DontCare;
  2255. if(!(h = CreateThread(NULL,
  2256. 0,
  2257. PnPInitializationThread,
  2258. NULL,
  2259. 0,
  2260. &DontCare))) {
  2261. SetuplogError(
  2262. LogSevError,
  2263. SETUPLOG_USE_MESSAGEID,
  2264. MSG_LOG_PNPINIT_FAILED,
  2265. GetLastError(),0,0);
  2266. }
  2267. return h;
  2268. }
  2269. DWORD
  2270. PnPInitializationThread(
  2271. IN PVOID ThreadParam
  2272. )
  2273. /*++
  2274. Routine Description:
  2275. This routine handles the PnP operations that go on asynchronously to the rest of the
  2276. system installation. This thread operates silently, and the only clue the user will
  2277. have that it's running is that their disk will be working (precompiling INFs, etc.),
  2278. while they're interacting with the UI.
  2279. Arguments:
  2280. ThreadParam - ignored.
  2281. Return Value:
  2282. If successful, the return value is NO_ERROR, otherwise, it is a Win32 error code.
  2283. No one cares about this thread's success or failure (yet).
  2284. --*/
  2285. {
  2286. HINF PnPSysSetupInf;
  2287. INFCONTEXT InfContext;
  2288. DWORD Err = NO_ERROR;
  2289. HDEVINFO hDevInfo;
  2290. DWORD i, j, BufferLen;
  2291. PWSTR DirPathEnd;
  2292. SC_HANDLE SCMHandle, ServiceHandle;
  2293. SERVICE_STATUS ServiceStatus;
  2294. WCHAR CharBuffer[MAX_PATH];
  2295. GUID ClassGuid;
  2296. SP_DEVINFO_DATA DeviceInfoData;
  2297. SP_DEVINSTALL_PARAMS DevInstallParams;
  2298. UNREFERENCED_PARAMETER(ThreadParam);
  2299. //
  2300. // Retrieve a list of all devices of unknown class. We will process the device information
  2301. // elements in this list to do the migration.
  2302. //
  2303. if((hDevInfo = SetupDiGetClassDevs((LPGUID)&GUID_DEVCLASS_LEGACYDRIVER,
  2304. L"Root",
  2305. NULL,
  2306. 0)) != INVALID_HANDLE_VALUE) {
  2307. //
  2308. // First, migrate any display devices. (As a side effect, every device instance that
  2309. // this routine doesn't migrate is returned with its ClassInstallReserved field set to
  2310. // point to the corresponding service's configuration information.)
  2311. //
  2312. MigrateLegacyDisplayDevices(hDevInfo);
  2313. //
  2314. // Enumerate each device information element in the set, freeing any remaining service
  2315. // configs.
  2316. //
  2317. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  2318. DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  2319. for(i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++) {
  2320. if(SetupDiGetDeviceInstallParams(hDevInfo, &DeviceInfoData, &DevInstallParams)) {
  2321. //
  2322. // A non-zero ClassInstallReserved field means we have to free the associated
  2323. // service config.
  2324. //
  2325. if(DevInstallParams.ClassInstallReserved) {
  2326. MyFree((PVOID)(DevInstallParams.ClassInstallReserved));
  2327. }
  2328. }
  2329. }
  2330. SetupDiDestroyDeviceInfoList(hDevInfo);
  2331. }
  2332. return Err;
  2333. }
  2334. VOID
  2335. MigrateLegacyDisplayDevices(
  2336. IN HDEVINFO hDevInfo
  2337. )
  2338. /*++
  2339. Routine Description:
  2340. This routine examines each device in the supplied device information set,
  2341. looking for elements controlled by a driver that is a member of the "Video"
  2342. load order group. For any such elements that it finds, it converts the
  2343. element to be of class "Display". If the device is not found to be of
  2344. class "Display", then the service configuration (which we retrieved to make
  2345. the determination), is stored away in the device install params as the
  2346. ClassInstallReserved value. This may be used by the caller for other
  2347. migration purposes, although presently it is not used. After calling this
  2348. routine, it is the caller's responsibility to loop through all devices in
  2349. this hDevInfo set, and free the ClassInstallReserved data (via MyFree) for
  2350. each device that has a non-zero value.
  2351. Arguments:
  2352. hDevInfo - Supplies a handle to the device information set containing all
  2353. devices of class "Unknown".
  2354. Return Value:
  2355. None.
  2356. --*/
  2357. {
  2358. SC_HANDLE SCMHandle, ServiceHandle;
  2359. DWORD i;
  2360. SP_DEVINFO_DATA DevInfoData, DisplayDevInfoData;
  2361. WCHAR ServiceName[MAX_SERVICE_NAME_LEN];
  2362. LPQUERY_SERVICE_CONFIG ServiceConfig;
  2363. HDEVINFO TempDevInfoSet = INVALID_HANDLE_VALUE;
  2364. WCHAR DevInstId[MAX_DEVICE_ID_LEN];
  2365. SP_DEVINSTALL_PARAMS DevInstallParams;
  2366. //
  2367. // First, open a handle to the Service Controller.
  2368. //
  2369. if(!(SCMHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
  2370. //
  2371. // If this fails, there's nothing we can do.
  2372. //
  2373. return;
  2374. }
  2375. DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  2376. DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  2377. for(i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DevInfoData); i++) {
  2378. //
  2379. // Retrieve the name of the controlling service for this device instance.
  2380. //
  2381. if(!SetupDiGetDeviceRegistryProperty(hDevInfo,
  2382. &DevInfoData,
  2383. SPDRP_SERVICE,
  2384. NULL,
  2385. (PBYTE)ServiceName,
  2386. sizeof(ServiceName),
  2387. NULL)) {
  2388. //
  2389. // No controlling service listed--just skip this element and continue
  2390. // with the next one.
  2391. //
  2392. continue;
  2393. }
  2394. //
  2395. // Open a handle to this service.
  2396. //
  2397. if(!(ServiceHandle = OpenService(SCMHandle, ServiceName, SERVICE_ALL_ACCESS))) {
  2398. continue;
  2399. }
  2400. //
  2401. // Now retrieve the service's configuration information.
  2402. //
  2403. if(pSetupRetrieveServiceConfig(ServiceHandle, &ServiceConfig) == NO_ERROR) {
  2404. //
  2405. // If this is a SERVICE_KERNEL_DRIVER that is a member of the "Video" load order
  2406. // group, then we have ourselves a display device.
  2407. //
  2408. if((ServiceConfig->dwServiceType == SERVICE_KERNEL_DRIVER) &&
  2409. ServiceConfig->lpLoadOrderGroup &&
  2410. !lstrcmpi(ServiceConfig->lpLoadOrderGroup, L"Video")) {
  2411. //
  2412. // If we haven't already done so, create a new device information set without
  2413. // an associated class, to hold our element while we munge it.
  2414. //
  2415. if(TempDevInfoSet == INVALID_HANDLE_VALUE) {
  2416. TempDevInfoSet = SetupDiCreateDeviceInfoList(NULL, NULL);
  2417. }
  2418. if(TempDevInfoSet != INVALID_HANDLE_VALUE) {
  2419. //
  2420. // OK, we have a working space to hold this element while we change its class.
  2421. // Retrieve the name of this device instance.
  2422. //
  2423. if(!SetupDiGetDeviceInstanceId(hDevInfo,
  2424. &DevInfoData,
  2425. DevInstId,
  2426. SIZECHARS(DevInstId),
  2427. NULL)) {
  2428. *DevInstId = L'\0';
  2429. }
  2430. //
  2431. // Now open this element in our new, class-agnostic set.
  2432. //
  2433. DisplayDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  2434. if(SetupDiOpenDeviceInfo(TempDevInfoSet,
  2435. DevInstId,
  2436. NULL,
  2437. 0,
  2438. &DisplayDevInfoData)) {
  2439. //
  2440. // Now set the device's ClassGUID property to the Display class GUID. The
  2441. // API will take care of cleaning up the old driver keys, etc.
  2442. //
  2443. SetupDiSetDeviceRegistryProperty(TempDevInfoSet,
  2444. &DisplayDevInfoData,
  2445. SPDRP_CLASSGUID,
  2446. (PBYTE)szDisplayClassGuid,
  2447. sizeof(szDisplayClassGuid)
  2448. );
  2449. }
  2450. }
  2451. MyFree(ServiceConfig);
  2452. } else {
  2453. //
  2454. // This device information element isn't a Display device. If
  2455. // the service isn't disabled, then store the service
  2456. // configuration information away in the device install params,
  2457. // for use later.
  2458. //
  2459. if((ServiceConfig->dwStartType != SERVICE_DISABLED) &&
  2460. SetupDiGetDeviceInstallParams(hDevInfo, &DevInfoData, &DevInstallParams)) {
  2461. DevInstallParams.ClassInstallReserved = (ULONG_PTR)ServiceConfig;
  2462. if(SetupDiSetDeviceInstallParams(hDevInfo, &DevInfoData, &DevInstallParams)) {
  2463. //
  2464. // We successfully stored a pointer to the
  2465. // ServiceConfig information. Set our pointer to NULL,
  2466. // so we won't try to free the buffer.
  2467. //
  2468. ServiceConfig = NULL;
  2469. }
  2470. }
  2471. //
  2472. // If we get to here, and ServiceConfig isn't NULL, then we
  2473. // need to free it.
  2474. //
  2475. if(ServiceConfig) {
  2476. MyFree(ServiceConfig);
  2477. }
  2478. }
  2479. }
  2480. CloseServiceHandle(ServiceHandle);
  2481. }
  2482. CloseServiceHandle(SCMHandle);
  2483. if(TempDevInfoSet != INVALID_HANDLE_VALUE) {
  2484. SetupDiDestroyDeviceInfoList(TempDevInfoSet);
  2485. }
  2486. }
  2487. BOOL
  2488. DriverNodeSupportsNT(
  2489. IN HDEVINFO DeviceInfoSet,
  2490. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  2491. )
  2492. /*++
  2493. Routine Description:
  2494. This routine determines whether the driver node selected for the specified parameters
  2495. support Windows NT. This determination is made based on whether or not the driver node
  2496. has a service install section.
  2497. Arguments:
  2498. DeviceInfoSet - Supplies a handle to the device information set
  2499. DeviceInfoData - Optionally, supplies the address of the device information element
  2500. within the set for which a driver node is selected. If this parameter is not
  2501. specified, then the driver node selected from the global class driver list will
  2502. be used instead.
  2503. Return Value:
  2504. If the driver node supports NT, the return value is TRUE, otherwise, it is FALSE (if
  2505. any errors are encountered, FALSE is also returned).
  2506. --*/
  2507. {
  2508. SP_DRVINFO_DATA DriverInfoData;
  2509. SP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
  2510. HINF hInf;
  2511. WCHAR ActualSectionName[255]; // real max. section length as defined in ..\setupapi\inf.h
  2512. DWORD ActualSectionNameLen;
  2513. LONG LineCount;
  2514. //
  2515. // First, retrieve the selected driver node.
  2516. //
  2517. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  2518. if(!SetupDiGetSelectedDriver(DeviceInfoSet, DeviceInfoData, &DriverInfoData)) {
  2519. return FALSE;
  2520. }
  2521. //
  2522. // Now, find out what INF it came from.
  2523. //
  2524. DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  2525. if(!SetupDiGetDriverInfoDetail(DeviceInfoSet,
  2526. DeviceInfoData,
  2527. &DriverInfoData,
  2528. &DriverInfoDetailData,
  2529. sizeof(DriverInfoDetailData),
  2530. NULL) &&
  2531. (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
  2532. {
  2533. return FALSE;
  2534. }
  2535. //
  2536. // Open the associated INF file.
  2537. //
  2538. if((hInf = SetupOpenInfFile(DriverInfoDetailData.InfFileName,
  2539. NULL,
  2540. INF_STYLE_WIN4,
  2541. NULL)) == INVALID_HANDLE_VALUE) {
  2542. return TRUE;
  2543. }
  2544. //
  2545. // Retrieve the actual name of the install section to be used for this driver node.
  2546. //
  2547. SetupDiGetActualSectionToInstall(hInf,
  2548. DriverInfoDetailData.SectionName,
  2549. ActualSectionName,
  2550. SIZECHARS(ActualSectionName),
  2551. &ActualSectionNameLen,
  2552. NULL
  2553. );
  2554. //
  2555. // Generate the service install section name, and see if it exists.
  2556. //
  2557. CopyMemory(&(ActualSectionName[ActualSectionNameLen - 1]),
  2558. SVCINSTALL_SECTION_SUFFIX,
  2559. sizeof(SVCINSTALL_SECTION_SUFFIX)
  2560. );
  2561. LineCount = SetupGetLineCount(hInf, ActualSectionName);
  2562. SetupCloseInfFile(hInf);
  2563. return (LineCount != -1);
  2564. }
  2565. DWORD
  2566. DisableService(
  2567. IN LPTSTR ServiceName
  2568. )
  2569. /*++
  2570. Routine Description:
  2571. This routine sets the start configuration setting of the named service to disabled
  2572. Arguments:
  2573. ServiceName - the name of the service to disable
  2574. Return Value:
  2575. If successful, the return value is NO_ERROR, otherwise, it is a Win32 error code.
  2576. Remarks:
  2577. This operation will fail if the SCM database remains locked for a long period (see
  2578. pSetupAcquireSCMLock for detail)
  2579. --*/
  2580. {
  2581. DWORD Err = NO_ERROR;
  2582. SC_HANDLE SCMHandle, ServiceHandle;
  2583. SC_LOCK SCMLock;
  2584. //
  2585. // Open a handle to Service Control Manager
  2586. //
  2587. if(!(SCMHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
  2588. Err = GetLastError();
  2589. goto clean0;
  2590. }
  2591. //
  2592. // Lock the SCM database
  2593. //
  2594. SetupDebugPrint1(L"LegacyDriver_OnApply: Locking ServiceDatabase for service %s", ServiceName);
  2595. if((Err = pSetupAcquireSCMLock(SCMHandle, &SCMLock)) != NO_ERROR) {
  2596. goto clean1;
  2597. }
  2598. //
  2599. // Open a handle to this service
  2600. //
  2601. if(!(ServiceHandle = OpenService(SCMHandle, ServiceName, SERVICE_CHANGE_CONFIG))) {
  2602. Err = GetLastError();
  2603. goto clean2;
  2604. }
  2605. //
  2606. // Perform change service config
  2607. //
  2608. if(!ChangeServiceConfig(ServiceHandle,
  2609. SERVICE_NO_CHANGE,
  2610. SERVICE_DISABLED,
  2611. SERVICE_NO_CHANGE,
  2612. NULL,
  2613. NULL,
  2614. NULL,
  2615. NULL,
  2616. NULL,
  2617. NULL,
  2618. NULL)) {
  2619. Err = GetLastError();
  2620. }
  2621. //
  2622. // Close handle to service
  2623. //
  2624. CloseServiceHandle(ServiceHandle);
  2625. clean2:
  2626. //
  2627. // Unlock the SCM database
  2628. //
  2629. UnlockServiceDatabase(SCMLock);
  2630. SetupDebugPrint1(L"LegacyDriver_OnApply: Unlocked ServiceDatabase for service %s", ServiceName);
  2631. clean1:
  2632. //
  2633. // Close handle to Service Control Manager
  2634. //
  2635. CloseServiceHandle(SCMHandle);
  2636. clean0:
  2637. return Err;
  2638. }
  2639. DWORD
  2640. RetrieveDriversStatus(
  2641. IN SC_HANDLE SCMHandle,
  2642. OUT LPENUM_SERVICE_STATUS *ppServices,
  2643. OUT LPDWORD pServicesCount
  2644. )
  2645. /*++
  2646. Routine Description:
  2647. This routine allocates a buffer to hold the status information for all the driver
  2648. services in the specified SCM database and retrieves that information into the
  2649. buffer. The caller is responsible for freeing the buffer.
  2650. Arguments:
  2651. SCMHandle - supplies a handle to the service control manager
  2652. ppServices - supplies the address of an ENUM_SERVICE_STATUS pointer that receives
  2653. the address of the allocated buffer containing the requested information.
  2654. pServicesCount - supplies the address of a variable that receives the number of elements
  2655. in the returned ppServices array
  2656. Return Value:
  2657. If successful, the return value is NO_ERROR, otherwise, it is a Win32 error code.
  2658. Remarks:
  2659. The pointer whose address is contained in ppServices is guaranteed to be NULL upon
  2660. return if any error occurred.
  2661. --*/
  2662. {
  2663. DWORD CurrentSize = 0, BytesNeeded = 0, ResumeHandle = 0, Err = NO_ERROR;
  2664. LPENUM_SERVICE_STATUS Buffer = NULL;
  2665. *ppServices = NULL;
  2666. *pServicesCount = 0;
  2667. while(!EnumServicesStatus(SCMHandle,
  2668. SERVICE_DRIVER,
  2669. SERVICE_ACTIVE | SERVICE_INACTIVE,
  2670. Buffer,
  2671. CurrentSize,
  2672. &BytesNeeded,
  2673. pServicesCount,
  2674. &ResumeHandle)) {
  2675. if((Err = GetLastError()) == ERROR_MORE_DATA) {
  2676. //
  2677. // Resize the buffer
  2678. //
  2679. if(!(Buffer = MyRealloc(Buffer, CurrentSize+BytesNeeded))) {
  2680. //
  2681. // Can't resize buffer - free resources and report error
  2682. //
  2683. if( *ppServices ) {
  2684. MyFree(*ppServices);
  2685. }
  2686. return ERROR_NOT_ENOUGH_MEMORY;
  2687. }
  2688. *ppServices = Buffer;
  2689. //
  2690. // Advance to the new space in the buffer
  2691. //
  2692. Buffer += CurrentSize;
  2693. CurrentSize += BytesNeeded;
  2694. } else {
  2695. //
  2696. // An error we can't handle
  2697. //
  2698. if( *ppServices ) {
  2699. MyFree(*ppServices);
  2700. }
  2701. return Err;
  2702. }
  2703. }
  2704. return NO_ERROR;
  2705. }
  2706. DWORD
  2707. IsOnlyKeyboardDriver(
  2708. IN PCWSTR ServiceName,
  2709. OUT PBOOL pResult
  2710. )
  2711. /*++
  2712. Routine Description:
  2713. This routines examines all the drivers in the system and determines if the named
  2714. driver service is the only one that controls the keyboard
  2715. Arguments:
  2716. ServiceName - supplies the name of the driver service
  2717. pResult - pointer to a boolean value that receives the result
  2718. Return Value:
  2719. NO_ERROR is the routine succedes, otherwise a Win32 error code
  2720. Remarks:
  2721. The test to determine if another keyboard driver is available is based on membership
  2722. of the keyboard load order group. All members of this group are assumed to be capable of
  2723. controling the keyboard.
  2724. --*/
  2725. {
  2726. SC_HANDLE SCMHandle, ServiceHandle;
  2727. LPENUM_SERVICE_STATUS pServices = NULL;
  2728. DWORD ServicesCount, Count, Err = NO_ERROR;
  2729. LPQUERY_SERVICE_CONFIG pServiceConfig;
  2730. MYASSERT(pResult);
  2731. *pResult = TRUE;
  2732. //
  2733. // Open a handle to Service Control Manager
  2734. //
  2735. if(!(SCMHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
  2736. Err = GetLastError();
  2737. goto clean0;
  2738. }
  2739. //
  2740. // Get a list of all the driver services and their stati
  2741. //
  2742. if((Err = RetrieveDriversStatus(SCMHandle, &pServices, &ServicesCount)) != NO_ERROR) {
  2743. goto clean1;
  2744. }
  2745. MYASSERT(pServices);
  2746. //
  2747. // Examine the configuration of each service
  2748. //
  2749. for(Count=0; Count < ServicesCount; Count++) {
  2750. //
  2751. // Check this is not our new service
  2752. //
  2753. if(lstrcmpi(pServices[Count].lpServiceName, ServiceName)) {
  2754. //
  2755. // Open a handle to this service
  2756. //
  2757. if(!(ServiceHandle = OpenService(SCMHandle,
  2758. pServices[Count].lpServiceName,
  2759. SERVICE_QUERY_CONFIG))) {
  2760. //
  2761. // We can't open a service handle then record the error and continue
  2762. //
  2763. Err = GetLastError();
  2764. continue;
  2765. }
  2766. //
  2767. // Get this services configuration data
  2768. //
  2769. pServiceConfig = NULL;
  2770. if((Err = pSetupRetrieveServiceConfig(ServiceHandle, &pServiceConfig)) != NO_ERROR) {
  2771. //
  2772. // We can't get service config then free any buffer, close the service
  2773. // handle and continue, the error has been recorded
  2774. //
  2775. MyFree(pServiceConfig);
  2776. CloseServiceHandle(ServiceHandle);
  2777. continue;
  2778. }
  2779. MYASSERT(pServiceConfig);
  2780. //
  2781. // Check if it is in the keyboard load order group and it has a start of
  2782. // SERVICE_BOOT_START OR SERVICE_SYSTEM_START. Do the start compare first as
  2783. // it is less expensive
  2784. //
  2785. if((pServiceConfig->dwStartType == SERVICE_BOOT_START
  2786. || pServiceConfig->dwStartType == SERVICE_SYSTEM_START)
  2787. && !lstrcmpi(pServiceConfig->lpLoadOrderGroup, SZ_KEYBOARD_LOAD_ORDER_GROUP)) {
  2788. *pResult = FALSE;
  2789. }
  2790. //
  2791. // Release the buffer
  2792. //
  2793. MyFree(pServiceConfig);
  2794. //
  2795. // Close the service handle
  2796. //
  2797. CloseServiceHandle(ServiceHandle);
  2798. //
  2799. // If we have found another keyboard driver then break out of the loop
  2800. //
  2801. if(!*pResult) {
  2802. break;
  2803. }
  2804. }
  2805. }
  2806. //
  2807. // Deallocate the buffer allocated by RetrieveDriversStatus
  2808. //
  2809. MyFree(pServices);
  2810. clean1:
  2811. //
  2812. // Close handle to Service Control Manager
  2813. //
  2814. CloseServiceHandle(SCMHandle);
  2815. clean0:
  2816. //
  2817. // If an error occured in the loop - ie we didn't check all the services - but we did
  2818. // find another keyboard driver in those we did check then we can ignore the error
  2819. // otherwise we must report it
  2820. //
  2821. if(NO_ERROR != Err && FALSE == *pResult) {
  2822. Err = NO_ERROR;
  2823. }
  2824. return Err;
  2825. }
  2826. DWORD
  2827. GetServiceStartType(
  2828. IN PCWSTR ServiceName
  2829. )
  2830. /*++
  2831. Routine Description:
  2832. This routines examines all the drivers in the system and determines if the named
  2833. driver service is the only one that controls the keyboard
  2834. Arguments:
  2835. ServiceName - supplies the name of the driver service
  2836. pResult - pointer to a boolean value that receives the result
  2837. Return Value:
  2838. NO_ERROR is the routine succedes, otherwise a Win32 error code
  2839. Remarks:
  2840. The test to determine if another keyboard driver is available is based on membership
  2841. of the keyboard load order group. All members of this group are assumed to be capable of
  2842. controling the keyboard.
  2843. --*/
  2844. {
  2845. SC_HANDLE SCMHandle, ServiceHandle;
  2846. DWORD dwStartType = -1;
  2847. LPQUERY_SERVICE_CONFIG pServiceConfig;
  2848. //
  2849. // Open a handle to Service Control Manager
  2850. //
  2851. if (!(SCMHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
  2852. goto clean0;
  2853. }
  2854. //
  2855. // Open a handle to this service
  2856. //
  2857. if (!(ServiceHandle = OpenService(SCMHandle,
  2858. ServiceName,
  2859. SERVICE_QUERY_CONFIG))) {
  2860. goto clean0;
  2861. }
  2862. //
  2863. // Get this services configuration data
  2864. //
  2865. pServiceConfig = NULL;
  2866. if (pSetupRetrieveServiceConfig(ServiceHandle, &pServiceConfig) != NO_ERROR) {
  2867. goto clean1;
  2868. }
  2869. MYASSERT(pServiceConfig);
  2870. if( !pServiceConfig ) {
  2871. goto clean1;
  2872. }
  2873. //
  2874. // store the start type, clean up, and exit
  2875. //
  2876. dwStartType = pServiceConfig->dwStartType;
  2877. clean1:
  2878. if (pServiceConfig) {
  2879. MyFree(pServiceConfig);
  2880. }
  2881. //
  2882. // Close the service handle
  2883. //
  2884. CloseServiceHandle(ServiceHandle);
  2885. //
  2886. // Close handle to Service Control Manager
  2887. //
  2888. CloseServiceHandle(SCMHandle);
  2889. clean0:
  2890. return dwStartType;
  2891. }
  2892. LONG
  2893. CountDevicesControlled(
  2894. IN LPTSTR ServiceName
  2895. )
  2896. /*++
  2897. Routine Description:
  2898. This routine return the number of devices controlled by a given device service
  2899. based on information from the configuration manager
  2900. Arguments:
  2901. ServiceName - supplies the name of the driver service
  2902. Return Value:
  2903. The number of devices controlled by ServiceName
  2904. Remarks:
  2905. When an error occurs the value 0 is returned - as the only place this routine is used
  2906. is in a test for one driver installed or not this is legitimate. This is because the
  2907. configuration manager returns its own errors which are cannot be returned as Win32
  2908. error codes. A mapping of config manager to Win32 errors would resolve this.
  2909. --*/
  2910. {
  2911. ULONG BufferSize=1024;
  2912. LONG DeviceCount=-1;
  2913. CONFIGRET Err;
  2914. PTSTR pBuffer, pNext;
  2915. //
  2916. // Allocate a 1k buffer as a first attempt
  2917. //
  2918. if(!(pBuffer = MyMalloc(BufferSize))) {
  2919. goto clean0;
  2920. }
  2921. while((Err = CM_Get_Device_ID_List(ServiceName,
  2922. pBuffer,
  2923. BufferSize,
  2924. CM_GETIDLIST_FILTER_SERVICE)) != CR_SUCCESS) {
  2925. if(Err == CR_BUFFER_SMALL) {
  2926. //
  2927. // Find out how large a buffer is required
  2928. //
  2929. if(CM_Get_Device_ID_List_Size(&BufferSize,
  2930. ServiceName,
  2931. CM_GETIDLIST_FILTER_SERVICE) != CR_SUCCESS) {
  2932. //
  2933. // We can't calculate the size of the buffer required therefore we can't complete
  2934. //
  2935. goto clean0;
  2936. }
  2937. //
  2938. // Deallocate any old buffer
  2939. //
  2940. MyFree(pBuffer);
  2941. //
  2942. // Allocate new buffer
  2943. //
  2944. if(!(pBuffer = MyMalloc(BufferSize))) {
  2945. goto clean0;
  2946. }
  2947. } else {
  2948. //
  2949. // An error we can't handle - free up resources and return
  2950. //
  2951. goto clean1;
  2952. }
  2953. }
  2954. //
  2955. // Traverse the buffer counting the number of strings encountered
  2956. //
  2957. pNext = pBuffer;
  2958. DeviceCount = 0;
  2959. while(*pNext != (TCHAR)0) {
  2960. DeviceCount++;
  2961. pNext += lstrlen(pNext)+1;
  2962. }
  2963. clean1:
  2964. //
  2965. // Deallocate the buffer
  2966. //
  2967. MyFree(pBuffer);
  2968. clean0:
  2969. return DeviceCount;
  2970. }
  2971. DWORD
  2972. IsKeyboardDriver(
  2973. IN PCWSTR ServiceName,
  2974. OUT PBOOL pResult
  2975. )
  2976. /*++
  2977. Routine Description:
  2978. This routine examines all the drivers in the system and determines if the named
  2979. driver service is the only one that controls the keyboard.
  2980. Arguments:
  2981. ServiceName - supplies the name of the driver service
  2982. pResult - pointer to a boolean value that receives the result
  2983. Return Value:
  2984. NO_ERROR is the routine succedes, otherwise a Win32 error code
  2985. Remarks:
  2986. The test to determine if another keyboard driver is available is based on membership
  2987. of the keyboard load order group. All members of this group are assumed to be capable of
  2988. controling the keyboard.
  2989. --*/
  2990. {
  2991. SC_HANDLE SCMHandle, ServiceHandle;
  2992. LPENUM_SERVICE_STATUS pServices = NULL;
  2993. DWORD ServicesCount, Count, Err = NO_ERROR;
  2994. LPQUERY_SERVICE_CONFIG pServiceConfig;
  2995. MYASSERT(pResult);
  2996. //
  2997. // Open a handle to Service Control Manager
  2998. //
  2999. if(!(SCMHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
  3000. Err = GetLastError();
  3001. goto clean0;
  3002. }
  3003. //
  3004. // Open a handle to this service
  3005. //
  3006. if(!(ServiceHandle = OpenService(SCMHandle,
  3007. ServiceName,
  3008. SERVICE_QUERY_CONFIG))) {
  3009. Err = GetLastError();
  3010. goto clean1;
  3011. }
  3012. //
  3013. // Get this services configuration data
  3014. //
  3015. pServiceConfig = NULL;
  3016. if((Err = pSetupRetrieveServiceConfig(ServiceHandle, &pServiceConfig)) != NO_ERROR) {
  3017. goto clean2;
  3018. }
  3019. MYASSERT(pServiceConfig);
  3020. if( !pServiceConfig ) {
  3021. Err = GetLastError();
  3022. goto clean2;
  3023. }
  3024. //
  3025. // Check if it is in the keyboard load order group and it has a start of
  3026. // SERVICE_BOOT_START OR SERVICE_SYSTEM_START. Do the start compare first as
  3027. // it is less expensive
  3028. //
  3029. *pResult = (pServiceConfig->dwStartType == SERVICE_BOOT_START
  3030. || pServiceConfig->dwStartType == SERVICE_SYSTEM_START)
  3031. && !lstrcmpi(pServiceConfig->lpLoadOrderGroup, SZ_KEYBOARD_LOAD_ORDER_GROUP);
  3032. //
  3033. // Release the buffer
  3034. //
  3035. MyFree(pServiceConfig);
  3036. clean2:
  3037. //
  3038. // Close the service handle
  3039. //
  3040. CloseServiceHandle(ServiceHandle);
  3041. clean1:
  3042. //
  3043. // Close handle to Service Control Manager
  3044. //
  3045. CloseServiceHandle(SCMHandle);
  3046. clean0:
  3047. return Err;
  3048. }
  3049. VOID
  3050. ReplaceSlashWithHash(
  3051. IN PWSTR Str
  3052. )
  3053. /*++
  3054. Routine Description:
  3055. Replaces all backslash chars with hash chars so that the string can be used
  3056. as a key name in the registry
  3057. --*/
  3058. {
  3059. for ( ; *Str ; Str++) {
  3060. if (*Str == L'\\') {
  3061. *Str = L'#';
  3062. }
  3063. }
  3064. }
  3065. HANDLE
  3066. UtilpGetDeviceHandle(
  3067. HDEVINFO DevInfo,
  3068. PSP_DEVINFO_DATA DevInfoData,
  3069. LPGUID ClassGuid,
  3070. DWORD DesiredAccess
  3071. )
  3072. /*++
  3073. Routine Description:
  3074. gets a handle for a device
  3075. Arguments:
  3076. the name of the device to open
  3077. Return Value:
  3078. handle to the device opened, which must be later closed by the caller.
  3079. Notes:
  3080. this function is also in storage proppage (storprop.dll)
  3081. so please propogate fixes there as well
  3082. --*/
  3083. {
  3084. BOOL status;
  3085. ULONG i;
  3086. HANDLE fileHandle = INVALID_HANDLE_VALUE;
  3087. SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
  3088. HDEVINFO devInfoWithInterface = NULL;
  3089. PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL;
  3090. PTSTR deviceInstanceId = NULL;
  3091. TCHAR * devicePath = NULL;
  3092. ULONG deviceInterfaceDetailDataSize;
  3093. ULONG deviceInstanceIdSize;
  3094. //
  3095. // get the ID for this device
  3096. //
  3097. for (i=deviceInstanceIdSize=0; i<2; i++) {
  3098. if (deviceInstanceIdSize != 0) {
  3099. deviceInstanceId =
  3100. LocalAlloc(LPTR, deviceInstanceIdSize * sizeof(TCHAR));
  3101. if (deviceInstanceId == NULL) {
  3102. ChkPrintEx(("SysSetup.GetDeviceHandle => Unable to "
  3103. "allocate for deviceInstanceId\n"));
  3104. goto cleanup;
  3105. }
  3106. }
  3107. status = SetupDiGetDeviceInstanceId(DevInfo,
  3108. DevInfoData,
  3109. deviceInstanceId,
  3110. deviceInstanceIdSize,
  3111. &deviceInstanceIdSize
  3112. );
  3113. }
  3114. if (!status) {
  3115. ChkPrintEx(("SysSetup.GetDeviceHandle => Unable to get "
  3116. "Device IDs\n"));
  3117. goto cleanup;
  3118. }
  3119. //
  3120. // Get all the cdroms in the system
  3121. //
  3122. devInfoWithInterface = SetupDiGetClassDevs(ClassGuid,
  3123. deviceInstanceId,
  3124. NULL,
  3125. DIGCF_DEVICEINTERFACE
  3126. );
  3127. if (devInfoWithInterface == NULL) {
  3128. ChkPrintEx(("SysSetup.GetDeviceHandle => Unable to get "
  3129. "list of CdRom's in system\n"));
  3130. goto cleanup;
  3131. }
  3132. memset(&deviceInterfaceData, 0, sizeof(SP_DEVICE_INTERFACE_DATA));
  3133. deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  3134. status = SetupDiEnumDeviceInterfaces(devInfoWithInterface,
  3135. NULL,
  3136. ClassGuid,
  3137. 0,
  3138. &deviceInterfaceData
  3139. );
  3140. if (!status) {
  3141. ChkPrintEx(("SysSetup.GetDeviceHandle => Unable to get "
  3142. "SP_DEVICE_INTERFACE_DATA\n"));
  3143. goto cleanup;
  3144. }
  3145. for (i=deviceInterfaceDetailDataSize=0; i<2; i++) {
  3146. if (deviceInterfaceDetailDataSize != 0) {
  3147. deviceInterfaceDetailData =
  3148. LocalAlloc (LPTR, deviceInterfaceDetailDataSize);
  3149. if (deviceInterfaceDetailData == NULL) {
  3150. ChkPrintEx(("SysSetup.GetDeviceHandle => Unable to "
  3151. "allocate for deviceInterfaceDetailData\n"));
  3152. goto cleanup;
  3153. }
  3154. deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
  3155. }
  3156. status = SetupDiGetDeviceInterfaceDetail(devInfoWithInterface,
  3157. &deviceInterfaceData,
  3158. deviceInterfaceDetailData,
  3159. deviceInterfaceDetailDataSize,
  3160. &deviceInterfaceDetailDataSize,
  3161. NULL);
  3162. }
  3163. if (!status) {
  3164. ChkPrintEx(("SysSetup.GetDeviceHandle => Unable to get "
  3165. "DeviceInterfaceDetail\n"));
  3166. goto cleanup;
  3167. }
  3168. devicePath = LocalAlloc(LPTR, deviceInterfaceDetailDataSize);
  3169. if (devicePath == NULL) {
  3170. ChkPrintEx(("SysSetup.GetDeviceHandle => Unable to alloc %x "
  3171. "bytes for devicePath\n"));
  3172. goto cleanup;
  3173. }
  3174. memcpy (devicePath,
  3175. deviceInterfaceDetailData->DevicePath,
  3176. deviceInterfaceDetailDataSize);
  3177. fileHandle = CreateFile(devicePath,
  3178. DesiredAccess,
  3179. FILE_SHARE_READ | FILE_SHARE_WRITE,
  3180. NULL,
  3181. OPEN_EXISTING,
  3182. 0,
  3183. NULL);
  3184. if (fileHandle == INVALID_HANDLE_VALUE) {
  3185. ChkPrintEx(("SysSetup.GetDeviceHandle => Final CreateFile() "
  3186. "failed\n"));
  3187. goto cleanup;
  3188. }
  3189. ChkPrintEx(("SysSetup.GetDeviceHandle => handle %x opened\n",
  3190. fileHandle));
  3191. cleanup:
  3192. if (devInfoWithInterface != NULL) {
  3193. SetupDiDestroyDeviceInfoList(devInfoWithInterface);
  3194. }
  3195. if (deviceInterfaceDetailData != NULL) {
  3196. LocalFree (deviceInterfaceDetailData);
  3197. }
  3198. if (devicePath != NULL) {
  3199. LocalFree (devicePath);
  3200. }
  3201. return fileHandle;
  3202. }
  3203. DWORD
  3204. CriticalDeviceCoInstaller(
  3205. IN DI_FUNCTION InstallFunction,
  3206. IN HDEVINFO DeviceInfoSet,
  3207. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  3208. IN OUT PCOINSTALLER_CONTEXT_DATA Context
  3209. )
  3210. /*++
  3211. Routine Description:
  3212. This routine acts as a co-installer for critical devices. It is presently
  3213. registered (via hivesys.inf) for CDROM, DiskDrive, System, Scsi, Hdc, and
  3214. Keyboard classes.
  3215. The purpose of this co-installer is to save away the services used by these
  3216. classes of device into the CriticalDeviceDatabase registry key. The reason
  3217. for this is so that we can determine what drivers should be used for new
  3218. critical devices that are found while the system is booting, and enable
  3219. them at that time. This solves the problem that arises when a device that
  3220. is critical to getting the system up and running (such as the boot device),
  3221. is moved to a new location. When we find a new critical device for which
  3222. we know what service to start, we can start the device and continue to boot
  3223. without failure.
  3224. Arguments:
  3225. InstallFunction - Specifies the device installer function code indicating
  3226. the action being performed.
  3227. DeviceInfoSet - Supplies a handle to the device information set being
  3228. acted upon by this install action.
  3229. DeviceInfoData - Optionally, supplies the address of a device information
  3230. element being acted upon by this install action.
  3231. Context - Supplies the installation context that is per-install request and
  3232. per-coinstaller.
  3233. Return Value:
  3234. For pre-processing, this function only cares about DIF_INSTALLDEVICE. For
  3235. all other DIF requests, it returns NO_ERROR. For DIF_INSTALLDEVICE, it
  3236. will request post-processing by returning ERROR_DI_POSTPROCESSING_REQUIRED
  3237. (or catastrophic error such as ERROR_NOT_ENOUGH_MEMORY).
  3238. For post-processing, this function will always propagate the install result
  3239. passed in to it via the co-installer Context structure.
  3240. --*/
  3241. {
  3242. HKEY hkDrv, hkCDD;
  3243. DWORD matchingDeviceIdSize, serviceNameSize, classGUIDSize, lowerFiltersSize,
  3244. upperFiltersSize, Err, disposition, driverSize;
  3245. TCHAR serviceName[MAX_SERVICE_NAME_LEN],
  3246. classGUID[GUID_STRING_LEN],
  3247. matchingDeviceId[MAX_DEVICE_ID_LEN];
  3248. PCTSTR driverMatch = TEXT("\\Driver");
  3249. PTSTR lowerFilters, upperFilters;
  3250. BOOL foundService, foundClassGUID, foundLowerFilters, foundUpperFilters;
  3251. PCDC_CONTEXT CDCContext;
  3252. switch(InstallFunction) {
  3253. //
  3254. // We only care about DIF_INSTALLDEVICE...
  3255. //
  3256. case DIF_INSTALLDEVICE :
  3257. if(Context->PostProcessing) {
  3258. //
  3259. // Track whether or not we've populated the critical device
  3260. // database with the newly-installed settings.
  3261. //
  3262. BOOL CDDPopulated = FALSE;
  3263. //
  3264. // We're 'on the way out' of an installation. We may have some
  3265. // data squirrelled away for us while we were "on the way in".
  3266. //
  3267. CDCContext = (PCDC_CONTEXT)(Context->PrivateData);
  3268. //
  3269. // Make sure that the matchingDeviceId buffer is initialized to
  3270. // an empty string.
  3271. //
  3272. *matchingDeviceId = TEXT('\0');
  3273. //
  3274. // Initialize our lowerFilters and upperFilters buffer pointers
  3275. // to NULL, so we can track whether or not we've allocated
  3276. // memory that must be freed.
  3277. //
  3278. upperFilters = lowerFilters = NULL;
  3279. if (Context->InstallResult != NO_ERROR) {
  3280. //
  3281. // If an error occurred prior to this call, abort and
  3282. // propagate that error.
  3283. //
  3284. goto InstallDevPostProcExit;
  3285. }
  3286. //
  3287. // Get the serviceName for this device.
  3288. //
  3289. foundService = SetupDiGetDeviceRegistryProperty(
  3290. DeviceInfoSet,
  3291. DeviceInfoData,
  3292. SPDRP_SERVICE,
  3293. NULL,
  3294. (PBYTE)serviceName,
  3295. sizeof(serviceName),
  3296. &serviceNameSize);
  3297. if (foundService) {
  3298. //
  3299. // Make sure the service name isn't something like \Driver\PCI_HAL
  3300. //
  3301. driverSize = wcslen(driverMatch);
  3302. if (wcslen(serviceName) >= driverSize &&
  3303. _wcsnicmp(serviceName, driverMatch, driverSize) == 0) {
  3304. goto InstallDevPostProcExit;
  3305. }
  3306. }
  3307. foundClassGUID = SetupDiGetDeviceRegistryProperty(
  3308. DeviceInfoSet,
  3309. DeviceInfoData,
  3310. SPDRP_CLASSGUID,
  3311. NULL,
  3312. (PBYTE)classGUID,
  3313. sizeof(classGUID),
  3314. &classGUIDSize);
  3315. //
  3316. // The LowerFilters and UpperFilters properties are variable-
  3317. // length, so we must dynamically size buffers to accommodate
  3318. // their contents.
  3319. //
  3320. foundLowerFilters =
  3321. (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  3322. DeviceInfoData,
  3323. SPDRP_LOWERFILTERS,
  3324. NULL,
  3325. NULL,
  3326. 0,
  3327. &lowerFiltersSize)
  3328. && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  3329. && (lowerFiltersSize > sizeof(TCHAR)));
  3330. if(foundLowerFilters) {
  3331. lowerFilters = MyMalloc(lowerFiltersSize);
  3332. if(!lowerFilters) {
  3333. goto InstallDevPostProcExit;
  3334. }
  3335. if(!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  3336. DeviceInfoData,
  3337. SPDRP_LOWERFILTERS,
  3338. NULL,
  3339. (PBYTE)lowerFilters,
  3340. lowerFiltersSize,
  3341. NULL)) {
  3342. //
  3343. // This shouldn't happen--we know we have a big enough
  3344. // buffer.
  3345. //
  3346. goto InstallDevPostProcExit;
  3347. }
  3348. }
  3349. foundUpperFilters =
  3350. (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  3351. DeviceInfoData,
  3352. SPDRP_UPPERFILTERS,
  3353. NULL,
  3354. NULL,
  3355. 0,
  3356. &upperFiltersSize)
  3357. && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  3358. && (upperFiltersSize > sizeof(TCHAR)));
  3359. if(foundUpperFilters) {
  3360. upperFilters = MyMalloc(upperFiltersSize);
  3361. if(!upperFilters) {
  3362. goto InstallDevPostProcExit;
  3363. }
  3364. if(!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  3365. DeviceInfoData,
  3366. SPDRP_UPPERFILTERS,
  3367. NULL,
  3368. (PBYTE)upperFilters,
  3369. upperFiltersSize,
  3370. NULL)) {
  3371. //
  3372. // This shouldn't happen--we know we have a big enough
  3373. // buffer.
  3374. //
  3375. goto InstallDevPostProcExit;
  3376. }
  3377. }
  3378. //
  3379. // Open Driver information key
  3380. //
  3381. if((hkDrv = SetupDiOpenDevRegKey(DeviceInfoSet,
  3382. DeviceInfoData,
  3383. DICS_FLAG_GLOBAL,
  3384. 0,
  3385. DIREG_DRV,
  3386. KEY_READ)) == INVALID_HANDLE_VALUE) {
  3387. goto InstallDevPostProcExit;
  3388. } else {
  3389. //
  3390. // Get matchingDeviceId
  3391. //
  3392. matchingDeviceIdSize = sizeof(matchingDeviceId);
  3393. Err = RegQueryValueEx(hkDrv,
  3394. REGSTR_VAL_MATCHINGDEVID,
  3395. NULL,
  3396. NULL,
  3397. (PBYTE)matchingDeviceId,
  3398. &matchingDeviceIdSize);
  3399. RegCloseKey(hkDrv);
  3400. if(Err != ERROR_SUCCESS) {
  3401. //
  3402. // Ensure that matchingDeviceId is still an empty string
  3403. //
  3404. *matchingDeviceId = TEXT('\0');
  3405. goto InstallDevPostProcExit;
  3406. }
  3407. }
  3408. hkCDD = OpenCDDRegistryKey(matchingDeviceId, TRUE);
  3409. if(hkCDD != INVALID_HANDLE_VALUE) {
  3410. //
  3411. // Store all the values (service, classguid, lower and upper
  3412. // filters, deleting any that aren't present in the newly installed
  3413. // device (which might have been present from a previous install)
  3414. //
  3415. if (foundService) {
  3416. RegSetValueEx(hkCDD,
  3417. REGSTR_VAL_SERVICE,
  3418. 0,
  3419. REG_SZ,
  3420. (PBYTE)&serviceName,
  3421. serviceNameSize);
  3422. }
  3423. else {
  3424. RegDeleteValue(hkCDD, REGSTR_VAL_SERVICE);
  3425. }
  3426. if (foundClassGUID) {
  3427. RegSetValueEx(hkCDD,
  3428. REGSTR_VAL_CLASSGUID,
  3429. 0,
  3430. REG_SZ,
  3431. (PBYTE)&classGUID,
  3432. classGUIDSize);
  3433. }
  3434. else {
  3435. RegDeleteValue(hkCDD, REGSTR_VAL_CLASSGUID);
  3436. }
  3437. if (foundLowerFilters) {
  3438. RegSetValueEx(hkCDD,
  3439. REGSTR_VAL_LOWERFILTERS,
  3440. 0,
  3441. REG_MULTI_SZ,
  3442. (PBYTE)lowerFilters,
  3443. lowerFiltersSize);
  3444. }
  3445. else {
  3446. RegDeleteValue(hkCDD, REGSTR_VAL_LOWERFILTERS);
  3447. }
  3448. if (foundUpperFilters) {
  3449. RegSetValueEx(hkCDD,
  3450. REGSTR_VAL_UPPERFILTERS,
  3451. 0,
  3452. REG_MULTI_SZ,
  3453. (PBYTE)upperFilters,
  3454. upperFiltersSize);
  3455. }
  3456. else {
  3457. RegDeleteValue(hkCDD, REGSTR_VAL_UPPERFILTERS);
  3458. }
  3459. RegCloseKey(hkCDD);
  3460. CDDPopulated = TRUE;
  3461. }
  3462. InstallDevPostProcExit:
  3463. if(lowerFilters) {
  3464. MyFree(lowerFilters);
  3465. }
  3466. if(upperFilters) {
  3467. MyFree(upperFilters);
  3468. }
  3469. if(CDCContext) {
  3470. //
  3471. // If we have a private context, that means that the device
  3472. // was installed previously, and that it had a CDD entry.
  3473. // We want to restore the previous controlling service
  3474. // stored in this CDD entry in the following two scenarios:
  3475. //
  3476. // 1. The CDD entry for the new installation is different
  3477. // than the old one.
  3478. // 2. We didn't end up populating the CDD entry with the
  3479. // newly-installed settings (probably because the
  3480. // InstallResult we were handed indicated that the
  3481. // install failed.
  3482. //
  3483. if(lstrcmpi(matchingDeviceId, CDCContext->OldMatchingDevId)
  3484. || !CDDPopulated) {
  3485. hkCDD = OpenCDDRegistryKey(CDCContext->OldMatchingDevId,
  3486. FALSE
  3487. );
  3488. if(hkCDD != INVALID_HANDLE_VALUE) {
  3489. if(*(CDCContext->OldServiceName)) {
  3490. RegSetValueEx(hkCDD,
  3491. REGSTR_VAL_SERVICE,
  3492. 0,
  3493. REG_SZ,
  3494. (PBYTE)(CDCContext->OldServiceName),
  3495. (lstrlen(CDCContext->OldServiceName) + 1) * sizeof(TCHAR)
  3496. );
  3497. } else {
  3498. RegDeleteValue(hkCDD, REGSTR_VAL_SERVICE);
  3499. }
  3500. RegCloseKey(hkCDD);
  3501. }
  3502. }
  3503. MyFree(CDCContext);
  3504. }
  3505. //
  3506. // Regardless of success or failure, we always want to propagate
  3507. // the existing install result. In other words, any failure we
  3508. // encounter in post-processing isn't considered critical.
  3509. //
  3510. return Context->InstallResult;
  3511. } else {
  3512. //
  3513. // We're "on the way in". We need to check and see if this
  3514. // device already has a critical device database entry
  3515. // associated with it. If so, then we want to remember the
  3516. // controlling service currently listed in the CDD (in case we
  3517. // need to restore it in post-processing if the install fails).
  3518. // We then clear this entry out of the CDD, so that, if a null
  3519. // driver install is taking place, that we won't try to re-apply
  3520. // the now-bogus CDD entry. This can get us into a nasty
  3521. // infinite loop in GUI setup where we keep finding the device
  3522. // because it's marked as finish-install, yet every time we
  3523. // install it, the (bogus) CDD entry gets re-applied, and the
  3524. // devnode gets marked yet again with finish-install.
  3525. //
  3526. // NTRAID #59238 1999/09/01 lonnym
  3527. // This fix is reliant upon the current
  3528. // (somewhat broken) behavior of the kernel-mode PnP manager's
  3529. // IopProcessCriticalDeviceRoutine. That routine will skip any
  3530. // CDD entries it finds that don't specify a controlling
  3531. // service. For NT5.1, we should remove this co-installer hack
  3532. // and fix the kernel-mode CDD functionality so that it is only
  3533. // applied when the devnode has a problem of not-configured (as
  3534. // opposed to its present behavior of attempting CDD
  3535. // application whenever there's no controlling service).
  3536. //
  3537. //
  3538. // First, open driver key to retrieve the current (i.e., pre-
  3539. // update) matching device ID.
  3540. //
  3541. if((hkDrv = SetupDiOpenDevRegKey(DeviceInfoSet,
  3542. DeviceInfoData,
  3543. DICS_FLAG_GLOBAL,
  3544. 0,
  3545. DIREG_DRV,
  3546. KEY_READ)) == INVALID_HANDLE_VALUE) {
  3547. //
  3548. // No need to allocate a private data structure to hand off
  3549. // to post-processing.
  3550. //
  3551. return ERROR_DI_POSTPROCESSING_REQUIRED;
  3552. } else {
  3553. //
  3554. // Get matchingDeviceId
  3555. //
  3556. matchingDeviceIdSize = sizeof(matchingDeviceId);
  3557. Err = RegQueryValueEx(hkDrv,
  3558. REGSTR_VAL_MATCHINGDEVID,
  3559. NULL,
  3560. NULL,
  3561. (PBYTE)matchingDeviceId,
  3562. &matchingDeviceIdSize);
  3563. RegCloseKey(hkDrv);
  3564. if (Err != ERROR_SUCCESS) {
  3565. //
  3566. // In this case as well, we've no need for private data
  3567. // during post-processing
  3568. //
  3569. return ERROR_DI_POSTPROCESSING_REQUIRED;
  3570. }
  3571. }
  3572. //
  3573. // If we get to here, then we've retrieved a "MatchingDeviceId"
  3574. // string from the device's driver key. Now let's see if there
  3575. // is a critical device entry for this ID...
  3576. //
  3577. hkCDD = OpenCDDRegistryKey(matchingDeviceId, FALSE);
  3578. if(hkCDD == INVALID_HANDLE_VALUE) {
  3579. //
  3580. // No existing CDD entry for this device, hence no need for
  3581. // private data to be passed off to post-processing.
  3582. //
  3583. return ERROR_DI_POSTPROCESSING_REQUIRED;
  3584. }
  3585. //
  3586. // If we get to here, we know that the device has been
  3587. // previously installed, and that there exists a CDD entry for
  3588. // that installation. We need to allocate a private data
  3589. // context structure to hand off to post-processing that
  3590. // contains (a) the currently in-effect matching device id, and
  3591. // (b) the currently in-effect controlling service (if any).
  3592. //
  3593. CDCContext = MyMalloc(sizeof(CDC_CONTEXT));
  3594. if(!CDCContext) {
  3595. //
  3596. // Can't allocate memory for our structure!
  3597. //
  3598. RegCloseKey(hkCDD);
  3599. return ERROR_NOT_ENOUGH_MEMORY;
  3600. }
  3601. lstrcpy(CDCContext->OldMatchingDevId, matchingDeviceId);
  3602. serviceNameSize = sizeof(CDCContext->OldServiceName);
  3603. Err = RegQueryValueEx(hkCDD,
  3604. REGSTR_VAL_SERVICE,
  3605. NULL,
  3606. NULL,
  3607. (PBYTE)(CDCContext->OldServiceName),
  3608. &serviceNameSize
  3609. );
  3610. if(Err == ERROR_SUCCESS) {
  3611. //
  3612. // Successfully retrieved the controlling service name--now
  3613. // delete the value entry.
  3614. //
  3615. RegDeleteValue(hkCDD, REGSTR_VAL_SERVICE);
  3616. } else {
  3617. //
  3618. // Couldn't retrieve controlling service name (most likely
  3619. // because there is none). Set OldServiceName to empty
  3620. // string.
  3621. //
  3622. *(CDCContext->OldServiceName) = TEXT('\0');
  3623. }
  3624. RegCloseKey(hkCDD);
  3625. Context->PrivateData = CDCContext;
  3626. return ERROR_DI_POSTPROCESSING_REQUIRED;
  3627. }
  3628. default :
  3629. //
  3630. // We should always be 'on the way in', since we never request
  3631. // postprocessing except for DIF_INSTALLDEVICE.
  3632. //
  3633. MYASSERT(!Context->PostProcessing);
  3634. return NO_ERROR;
  3635. }
  3636. }
  3637. HKEY
  3638. OpenCDDRegistryKey(
  3639. IN PCTSTR DeviceId,
  3640. IN BOOL Create
  3641. )
  3642. /*++
  3643. Routine Description:
  3644. This routine opens (and optionally, creates if necessary) a critical device
  3645. registry key entry for a specified device ID.
  3646. Arguments:
  3647. DeviceId - supplies the device ID identifying the desired critical device
  3648. database entry (registry key)
  3649. Create - if non-zero, the registry key will be created if it doesn't
  3650. already exist.
  3651. Return Value:
  3652. If successful, the return value is a handle to the requested registry key.
  3653. If failure, the return value is INVALID_HANDLE_VALUE.
  3654. --*/
  3655. {
  3656. TCHAR MungedDeviceId[MAX_DEVICE_ID_LEN];
  3657. HKEY hkParent, hkRet;
  3658. //
  3659. // Open or create for read/write access to key under
  3660. // HKLM\System\CurrentControlSet\Control\CriticalDeviceDatabase
  3661. //
  3662. if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  3663. REGSTR_PATH_CRITICALDEVICEDATABASE,
  3664. 0,
  3665. NULL,
  3666. REG_OPTION_NON_VOLATILE,
  3667. KEY_READ | KEY_WRITE,
  3668. NULL,
  3669. &hkParent,
  3670. NULL) != ERROR_SUCCESS) {
  3671. return INVALID_HANDLE_VALUE;
  3672. }
  3673. //
  3674. // Make a copy of the caller-supplied device ID so we can munge it.
  3675. //
  3676. lstrcpy(MungedDeviceId, DeviceId);
  3677. ReplaceSlashWithHash(MungedDeviceId);
  3678. if(Create) {
  3679. if(RegCreateKeyEx(hkParent,
  3680. MungedDeviceId,
  3681. 0,
  3682. NULL,
  3683. REG_OPTION_NON_VOLATILE,
  3684. KEY_READ | KEY_WRITE,
  3685. NULL,
  3686. &hkRet,
  3687. NULL) != ERROR_SUCCESS) {
  3688. hkRet = INVALID_HANDLE_VALUE;
  3689. }
  3690. } else {
  3691. if(RegOpenKeyEx(hkParent,
  3692. MungedDeviceId,
  3693. 0,
  3694. KEY_READ | KEY_WRITE,
  3695. &hkRet) != ERROR_SUCCESS) {
  3696. hkRet = INVALID_HANDLE_VALUE;
  3697. }
  3698. }
  3699. RegCloseKey(hkParent);
  3700. return hkRet;
  3701. }
  3702. DWORD
  3703. NtApmClassInstaller(
  3704. IN DI_FUNCTION DiFunction,
  3705. IN HDEVINFO DevInfoHandle,
  3706. IN PSP_DEVINFO_DATA DevInfoData OPTIONAL
  3707. )
  3708. /*++
  3709. Routine Description:
  3710. NOTE: When does Susan's clean up code run? When does the win0x
  3711. migration code run? Do we need to call off to either of
  3712. them in here?
  3713. NOTE: Be sure that this works at initial install AND when the
  3714. user does detect new hardare.
  3715. This is the class installer for nt apm support.
  3716. This routine installs, or thwarts installation, of the NT5 apm solution,
  3717. depending on whether the machine is an APCI machine, is an APM machine,
  3718. and has a good, bad, or unknown apm bios.
  3719. This version is copied directly from the battery class driver.
  3720. Arguments:
  3721. InstallFunction - Specifies the device installer function code indicating
  3722. the action being performed.
  3723. DeviceInfoSet - Supplies a handle to the device information set being
  3724. acted upon by this install action.
  3725. DeviceInfoData - Optionally, supplies the address of a device information
  3726. element being acted upon by this install action.
  3727. Return Value:
  3728. If this function successfully completed the requested action, the return
  3729. value is NO_ERROR.
  3730. If the default behavior is to be performed for the requested action, the
  3731. return value is ERROR_DI_DO_DEFAULT.
  3732. If an error occurred while attempting to perform the requested action, a
  3733. Win32 error code is returned.
  3734. --*/
  3735. {
  3736. DWORD status, worktype;
  3737. BOOLEAN InstallDisabled;
  3738. ChkPrintEx(("syssetup: NtApmClassInstaller:"));
  3739. ChkPrintEx(("DiFunction %08lx\n", DiFunction));
  3740. //
  3741. // Dispatch the InstallFunction
  3742. //
  3743. InstallDisabled = FALSE;
  3744. switch (DiFunction) {
  3745. ChkPrintEx(("syssetup: NtApmClassInstaller: DiFunction = %08lx\n",
  3746. DiFunction));
  3747. case DIF_FIRSTTIMESETUP:
  3748. case DIF_DETECT:
  3749. worktype = DecideNtApm();
  3750. //
  3751. // NOTE: We assume that if we say "do default" and we
  3752. // have not created a device info structure for
  3753. // ntapm, the installer will do *nothing*.
  3754. //
  3755. if (worktype == NTAPM_NOWORK) {
  3756. ChkPrintEx(("syssetup: NtApmClassInstaller returning ERROR_DI_DO_DEFAULT"));
  3757. return ERROR_DI_DO_DEFAULT;
  3758. }
  3759. if (worktype == NTAPM_INST_DISABLED) {
  3760. InstallDisabled = TRUE;
  3761. }
  3762. ChkPrintEx(("syssetup: NtApmClassInstaller: calling InstallNtApm\n"));
  3763. status = InstallNtApm(DevInfoHandle, InstallDisabled);
  3764. ChkPrintEx(("syssetup: NtApmClassInstaller: InstallNtApm returned "
  3765. "%08lx\n", status));
  3766. if (status == ERROR_SUCCESS) {
  3767. //
  3768. // Let the default device installer actually install ntapm.
  3769. //
  3770. status = ERROR_DI_DO_DEFAULT;
  3771. }
  3772. break;
  3773. case DIF_ALLOW_INSTALL:
  3774. //
  3775. // NOTE: If we are here, it means that either DIF_FIRSTIMESETUP
  3776. // has installed apm (either enabled or disabled) OR
  3777. // this is an upgrad of a machine where it was installed
  3778. // in the past. So all we want to do is make sure
  3779. // that if apm is currently disabled, it stays disabled.
  3780. //
  3781. ChkPrintEx(("syssetup: NtApmClassIntaller: DIF_ALLOW_INSTALL\n"));
  3782. return AllowInstallNtApm(DevInfoHandle, DevInfoData);
  3783. break;
  3784. case DIF_TROUBLESHOOTER:
  3785. ChkPrintEx(("syssetup: NtApmClassInstaller: DIF_TROUBLESHOOTER\n"));
  3786. return NO_ERROR;
  3787. break;
  3788. default:
  3789. //
  3790. // NOTE: We assume that if we say "do default" and we
  3791. // have not created a device info structure for ntapm,
  3792. // the installer will do *nothing*.
  3793. //
  3794. ChkPrintEx(("syssetup: NtApmClassInstaller: default:\n"));
  3795. status = ERROR_DI_DO_DEFAULT;
  3796. break;
  3797. }
  3798. ChkPrintEx(("syssetup: NtApmClassInstaller returning %08lx\n", status));
  3799. return status;
  3800. }
  3801. DWORD
  3802. DecideNtApm(
  3803. VOID
  3804. )
  3805. /*++
  3806. Routine Description:
  3807. This function decides if NtApm should be installed on the machine,
  3808. and if it should, whether it should be installed enabled or disabled.
  3809. This little bit of code is isolated here to make it easy to change
  3810. policies.
  3811. Arguments:
  3812. Return Value:
  3813. NTAPM_NOWORK - ACPI machine or no usable APM - do nothing
  3814. NTAPM_INST_DISABLED - APM machine, on neutral list, install disabled
  3815. NTAPM_INST_ENABLED - APM machine, on validated good list, install enabled
  3816. --*/
  3817. {
  3818. DWORD BiosType;
  3819. //
  3820. // NOTE: The following two tests are somewhat redundent.
  3821. // (In theory, you cannot be ApmLegalHal AND Acpi
  3822. // at the same time.) But, this belt and suspenders
  3823. // approach is very cheap, and will insure we do the
  3824. // right thing in certain upgrade and reinstall scenarios.
  3825. // So we leave both in.
  3826. //
  3827. ChkPrintEx(("syssetup: DecideNtApm: entered\n"));
  3828. if ( ! IsProductTypeApmLegal()) {
  3829. // it's not a workstation, so do nothing.
  3830. return NTAPM_NOWORK;
  3831. }
  3832. if (IsAcpiMachine()) {
  3833. //
  3834. // It's an ACPI machine, so do nothing
  3835. //
  3836. ChkPrintEx(("syssetup: DecideNtApm: acpi box, return NTAPM_NOWORK\n"));
  3837. return NTAPM_NOWORK;
  3838. }
  3839. if (IsApmLegalHalMachine() == FALSE) {
  3840. //
  3841. // It's NOT a standard Hal machine as required
  3842. // by ntapm, so do nothing.
  3843. //
  3844. ChkPrintEx(("syssetup: DecideNtApm: not apm legal, return NTAPM_NOWORK\n"));
  3845. return NTAPM_NOWORK;
  3846. }
  3847. BiosType = IsApmPresent();
  3848. if (BiosType == APM_ON_GOOD_LIST) {
  3849. ChkPrintEx(("syssetup: DecideNtApm: return NTAPM_INST_ENABLED\n"));
  3850. return NTAPM_INST_ENABLED;
  3851. } else if (BiosType == APM_NEUTRAL) {
  3852. ChkPrintEx(("syssetup: DecideNtApm: return NTAPM_INST_DISABLED\n"));
  3853. return NTAPM_INST_DISABLED;
  3854. } else {
  3855. ChkPrintEx(("syssetup: DecideNtApm: return NTAPM_NOWORK\n"));
  3856. return NTAPM_NOWORK;
  3857. }
  3858. }
  3859. DWORD
  3860. InstallNtApm(
  3861. IN HDEVINFO DevInfoHandle,
  3862. IN BOOLEAN InstallDisabled
  3863. )
  3864. /*++
  3865. Routine Description:
  3866. This function installs the composite battery if it hasn't already been
  3867. installed.
  3868. Arguments:
  3869. DevInfoHandle - Handle to a device information set
  3870. InstallDisabled - TRUE if caller wants us to install disabled
  3871. Return Value:
  3872. --*/
  3873. {
  3874. DWORD status;
  3875. SP_DRVINFO_DATA driverInfoData;
  3876. TCHAR tmpBuffer[100];
  3877. DWORD bufferLen;
  3878. PSP_DEVINFO_DATA DevInfoData;
  3879. SP_DEVINSTALL_PARAMS DevInstallParams;
  3880. ChkPrintEx(("syssetup: InstallNtApm: DevInfoHandle = %08lx installdisabled = %08lx\n", DevInfoHandle, InstallDisabled));
  3881. DevInfoData = LocalAlloc(LPTR, sizeof(SP_DEVINFO_DATA));
  3882. if ( ! DevInfoData) {
  3883. status = GetLastError();
  3884. goto clean0;
  3885. }
  3886. DevInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
  3887. DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  3888. //
  3889. // Attempt to manufacture a new device information element for the root enumerated
  3890. // ntapm device.
  3891. //
  3892. if(!SetupDiCreateDeviceInfo(DevInfoHandle,
  3893. TEXT("ROOT\\NTAPM\\0000"),
  3894. (LPGUID)&GUID_DEVCLASS_APMSUPPORT,
  3895. TEXT("NT Apm Legacy Support"),
  3896. NULL,
  3897. 0,
  3898. DevInfoData))
  3899. {
  3900. status = GetLastError();
  3901. if (status == ERROR_DEVINST_ALREADY_EXISTS) {
  3902. //
  3903. // NtApm is already installed.
  3904. //
  3905. ChkPrintEx(("ntapm Already Installed\n"));
  3906. status = ERROR_SUCCESS;
  3907. goto clean1;
  3908. } else {
  3909. ChkPrintEx(("Error creating ntapm devinfo - %x\n", status));
  3910. goto clean1;
  3911. }
  3912. }
  3913. //
  3914. // Set device to Install Disabled if the caller wants that
  3915. //
  3916. if (InstallDisabled) {
  3917. if (!SetupDiGetDeviceInstallParams(DevInfoHandle, DevInfoData, &DevInstallParams)) {
  3918. status = GetLastError();
  3919. goto clean1;
  3920. }
  3921. DevInstallParams.Flags |= DI_INSTALLDISABLED;
  3922. if (!SetupDiSetDeviceInstallParams(DevInfoHandle, DevInfoData, &DevInstallParams)) {
  3923. status = GetLastError();
  3924. goto clean1;
  3925. }
  3926. }
  3927. //
  3928. // Register the device so it is not a phantom anymore
  3929. //
  3930. if (!SetupDiRegisterDeviceInfo(DevInfoHandle, DevInfoData, 0, NULL, NULL, NULL)) {
  3931. status = GetLastError();
  3932. SetupDebugPrint1(L"Couldn't register device - %x\n", status);
  3933. goto clean3;
  3934. }
  3935. //
  3936. // Set the hardware ID. "NTAPM"
  3937. //
  3938. memset (tmpBuffer, 0, sizeof(tmpBuffer));
  3939. lstrcpy (tmpBuffer, TEXT("NTAPM"));
  3940. bufferLen = (lstrlen(tmpBuffer) + 1) * sizeof(TCHAR);
  3941. //SetupDebugPrint2(L"tmpBuffer - %ws\n with strlen = %x\n", tmpBuffer, bufferLen);
  3942. //SetupDebugPrint1(L"tmpBuffer@ = %08lx\n", tmpBuffer);
  3943. status = SetupDiSetDeviceRegistryProperty (
  3944. DevInfoHandle,
  3945. DevInfoData,
  3946. SPDRP_HARDWAREID,
  3947. (PBYTE)tmpBuffer,
  3948. bufferLen
  3949. );
  3950. if (!status) {
  3951. status = GetLastError();
  3952. //SetupDebugPrint1(L"Couldn't set the HardwareID - %x\n", status);
  3953. goto clean3;
  3954. }
  3955. //
  3956. // Build a compatible driver list for this new device...
  3957. //
  3958. if(!SetupDiBuildDriverInfoList(DevInfoHandle, DevInfoData, SPDIT_COMPATDRIVER)) {
  3959. status = GetLastError();
  3960. //SetupDebugPrint1(L"Couldn't build class driver list - %x\n", status);
  3961. goto clean3;
  3962. }
  3963. //
  3964. // Select the first driver in the list as this will be the most compatible
  3965. //
  3966. driverInfoData.cbSize = sizeof (SP_DRVINFO_DATA);
  3967. if (!SetupDiEnumDriverInfo(DevInfoHandle, DevInfoData, SPDIT_COMPATDRIVER, 0, &driverInfoData)) {
  3968. status = GetLastError();
  3969. //SetupDebugPrint1(L"Couldn't get driver list - %x\n", status);
  3970. goto clean3;
  3971. } else {
  3972. //SetupDebugPrint4(L"Driver info - \n"
  3973. // L"------------- DriverType %x\n"
  3974. // L"------------- Description %s\n"
  3975. // L"------------- MfgName %s\n"
  3976. // L"------------- ProviderName %s\n\n",
  3977. // driverInfoData.DriverType,
  3978. // driverInfoData.Description,
  3979. // driverInfoData.MfgName,
  3980. // driverInfoData.ProviderName);
  3981. if (!SetupDiSetSelectedDriver(DevInfoHandle, DevInfoData, &driverInfoData)) {
  3982. status = GetLastError();
  3983. //SetupDebugPrint1(L"Couldn't select driver - %x\n", status);
  3984. goto clean3;
  3985. }
  3986. }
  3987. if (!SetupDiInstallDevice (DevInfoHandle, DevInfoData)) {
  3988. status = GetLastError();
  3989. //SetupDebugPrint1(L"Couldn't install device - %x\n", status);
  3990. goto clean3;
  3991. }
  3992. //
  3993. // If we got here we were successful
  3994. //
  3995. status = ERROR_SUCCESS;
  3996. SetLastError (status);
  3997. goto clean1;
  3998. clean3:
  3999. SetupDiDeleteDeviceInfo (DevInfoHandle, DevInfoData);
  4000. clean1:
  4001. LocalFree (DevInfoData);
  4002. clean0:
  4003. return status;
  4004. }
  4005. DWORD
  4006. AllowInstallNtApm(
  4007. IN HDEVINFO DevInfoHandle,
  4008. IN PSP_DEVINFO_DATA DevInfoData OPTIONAL
  4009. )
  4010. /*++
  4011. Routine Description:
  4012. This function decides whether to allow install (which will do
  4013. an enabled install at least in the upgrade case) or force
  4014. an install disbled.
  4015. Arguments:
  4016. DevInfoHandle - Handle to a device information set
  4017. DeviceInfoData - Optionally, supplies the address of a device information
  4018. element being acted upon by this install action.
  4019. N.B. If this is null, we have a problem.
  4020. Return Value:
  4021. status.
  4022. --*/
  4023. {
  4024. ULONG DevStatus;
  4025. ULONG DevProblem;
  4026. SP_DEVINSTALL_PARAMS DevInstallParams = {0};
  4027. CONFIGRET Result;
  4028. ChkPrintEx(("syssetup: AllowInstallNtApm: entered\n"));
  4029. if ( ! IsProductTypeApmLegal()) {
  4030. // it's not a workstation, so disallow install
  4031. ChkPrintEx(("syssetup: AllowInstallNtApm #0: not a work station => return ERROR_DI_DONT_INSTALL\n"));
  4032. return ERROR_DI_DONT_INSTALL;
  4033. }
  4034. if (! DevInfoData) {
  4035. //
  4036. // If DevInfoData is null, we don't actually know
  4037. // what is going on, so say "OK" and hope for the best
  4038. //
  4039. ChkPrintEx(("sysetup: AllowInstallNtApm #1: no DevInfoData => return ERROR_DI_DO_DEFAULT\n"));
  4040. return ERROR_DI_DO_DEFAULT;
  4041. }
  4042. //
  4043. // Call the CM and ask it what it knows about this devinst
  4044. //
  4045. Result = CM_Get_DevNode_Status(&DevStatus, &DevProblem, DevInfoData->DevInst, 0);
  4046. ChkPrintEx(("syssetup: AllowInstallNtApm #2: DevStatus = %08lx\n", DevStatus));
  4047. ChkPrintEx(("syssetup: AllowInstallNtApm #3: DevProblem = %08lx\n", DevProblem));
  4048. if (Result != CR_SUCCESS) {
  4049. ChkPrintEx(("syssetup: AllowInstallNtApm #4: return ERROR_DI_DONT_INSTALL\n"));
  4050. return ERROR_DI_DONT_INSTALL;
  4051. }
  4052. if (DevStatus & DN_HAS_PROBLEM) {
  4053. if (DevProblem == CM_PROB_DISABLED) {
  4054. //
  4055. // it's supposed to be disabled
  4056. //
  4057. DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  4058. if (!SetupDiGetDeviceInstallParams(DevInfoHandle, DevInfoData, &DevInstallParams)) {
  4059. ChkPrintEx(("syssetup: AllowInstallNtApm #5: return ERROR_DI_DONT_INSTALL\n"));
  4060. return ERROR_DI_DONT_INSTALL;
  4061. }
  4062. DevInstallParams.Flags |= DI_INSTALLDISABLED;
  4063. if (!SetupDiSetDeviceInstallParams(DevInfoHandle, DevInfoData, &DevInstallParams)) {
  4064. ChkPrintEx(("syssetup: AllowInstallNtApm #6: return ERROR_DI_DONT_INSTALL\n"));
  4065. return ERROR_DI_DONT_INSTALL;
  4066. }
  4067. }
  4068. }
  4069. ChkPrintEx(("syssetup: AllowInstallNtApm #7: return ERROR_DI_DO_DEFAULT\n"));
  4070. return ERROR_DI_DO_DEFAULT;
  4071. }
  4072. BOOL
  4073. IsProductTypeApmLegal()
  4074. /*++
  4075. Routine Description:
  4076. Determines if we are running on workstation (win2000 pro) or not.
  4077. If we are, return TRUE. else return FALSE.
  4078. This is used to overcome weirdness in setup AND to prevent people from
  4079. getting themselves into trouble by allowing apm to run on a server.
  4080. Return Value:
  4081. TRUE - it's workstation, it's OK to run APM
  4082. FALSE - it's server, DON'T let APM run
  4083. --*/
  4084. {
  4085. OSVERSIONINFOEX OsVersionInfo;
  4086. OsVersionInfo.dwOSVersionInfoSize = sizeof(OsVersionInfo);
  4087. if (!GetVersionEx((OSVERSIONINFO *) &OsVersionInfo)) {
  4088. ChkPrintEx(("GetVersionEx failed, return server (FALSE)\n"));
  4089. return FALSE;
  4090. }
  4091. if (OsVersionInfo.wProductType == VER_NT_WORKSTATION) {
  4092. return TRUE;
  4093. }
  4094. return FALSE;
  4095. }
  4096. //
  4097. // Ideally these would be defined in a header file somewhere,
  4098. // but that's hard to do becuase they are set up in an INF.
  4099. // SO - simply be sure that they match up with these lines in
  4100. // biosinfo.inf:
  4101. //
  4102. // For KNOWN_BAD:
  4103. // [DisableApmAddReg]
  4104. // HKLM,System\CurrentControlSet\Control\Biosinfo\APM,Attributes,0x00010001,00000002
  4105. //
  4106. // For KNOWN_GOOD:
  4107. // [AutoEnableApmAddReg]
  4108. // HKLM,System\CurrentControlSet\Control\Biosinfo\APM,Attributes,0x00010001,00000001
  4109. //
  4110. #define APM_BIOS_KNOWN_GOOD 0x00000001
  4111. #define APM_BIOS_KNOWN_BAD 0x00000002
  4112. DWORD
  4113. IsApmPresent()
  4114. /*++
  4115. Routine Description:
  4116. IsApmPresent runs the same code as ntapm.sys does to decide
  4117. if ntdetect has found and reported a usable APM bios.
  4118. It then checks to see what, if any, bios lists this machine
  4119. and bios are one.
  4120. It factors this data together to report the existence/non-existence
  4121. of apm on the machine, and its usability and suitability.
  4122. Return Value:
  4123. APM_NOT_PRESENT - apm does not appear to be present on this machine
  4124. APM_PRESENT_BUT_NOT_USABLE - there appears to be an apm bios, but
  4125. it did not allow connection correctly (version or api support problem)
  4126. APM_ON_GOOD_LIST - there is a bios and it's on the good bios list
  4127. APM_NEUTRAL - there is a bios, it appears to be usable,
  4128. it is not on the good bios list, but it's also not
  4129. on the bad bios list.
  4130. APM_ON_BAD_LIST - there is a bios, but it's on the bad bios list.
  4131. --*/
  4132. {
  4133. //
  4134. // first part of this code is copied from ...\ntos\dd\ntapm\i386\apm.c
  4135. // keep it in sync with that code
  4136. //
  4137. UNICODE_STRING unicodeString, ConfigName, IdentName;
  4138. OBJECT_ATTRIBUTES objectAttributes;
  4139. HANDLE hMFunc, hBus, hGoodBad;
  4140. NTSTATUS status;
  4141. PCM_PARTIAL_RESOURCE_DESCRIPTOR PDesc;
  4142. PCM_FULL_RESOURCE_DESCRIPTOR Desc;
  4143. PKEY_VALUE_FULL_INFORMATION ValueInfo;
  4144. PKEY_VALUE_PARTIAL_INFORMATION pvpi;
  4145. PAPM_REGISTRY_INFO ApmEntry;
  4146. UCHAR buffer [sizeof(APM_REGISTRY_INFO) + 99];
  4147. WCHAR wstr[8];
  4148. ULONG i, j, Count, junk;
  4149. PWSTR p;
  4150. USHORT volatile Offset;
  4151. PULONG pdw;
  4152. DWORD BiosType;
  4153. // ----------------------------------------------------------------------
  4154. //
  4155. // First Part - See if ntdetect.com found APM....
  4156. //
  4157. // ----------------------------------------------------------------------
  4158. //
  4159. // Look in the registery for the "APM bus" data
  4160. //
  4161. RtlInitUnicodeString(&unicodeString, rgzMultiFunctionAdapter);
  4162. InitializeObjectAttributes(
  4163. &objectAttributes,
  4164. &unicodeString,
  4165. OBJ_CASE_INSENSITIVE,
  4166. NULL, // handle
  4167. NULL
  4168. );
  4169. status = NtOpenKey(&hMFunc, KEY_READ, &objectAttributes);
  4170. if (!NT_SUCCESS(status)) {
  4171. return APM_NOT_PRESENT;
  4172. }
  4173. unicodeString.Buffer = wstr;
  4174. unicodeString.MaximumLength = sizeof (wstr);
  4175. RtlInitUnicodeString(&ConfigName, rgzConfigurationData);
  4176. RtlInitUnicodeString(&IdentName, rgzIdentifier);
  4177. ValueInfo = (PKEY_VALUE_FULL_INFORMATION) buffer;
  4178. for (i=0; TRUE; i++) {
  4179. RtlIntegerToUnicodeString(i, 10, &unicodeString);
  4180. InitializeObjectAttributes(
  4181. &objectAttributes,
  4182. &unicodeString,
  4183. OBJ_CASE_INSENSITIVE,
  4184. hMFunc,
  4185. NULL
  4186. );
  4187. status = NtOpenKey(&hBus, KEY_READ, &objectAttributes);
  4188. if (!NT_SUCCESS(status)) {
  4189. //
  4190. // Out of Multifunction adapter entries...
  4191. //
  4192. NtClose(hMFunc);
  4193. return APM_NOT_PRESENT;
  4194. }
  4195. //
  4196. // Check the Indentifier to see if this is a APM entry
  4197. //
  4198. status = NtQueryValueKey (
  4199. hBus,
  4200. &IdentName,
  4201. KeyValueFullInformation,
  4202. ValueInfo,
  4203. sizeof (buffer),
  4204. &junk
  4205. );
  4206. if (!NT_SUCCESS (status)) {
  4207. NtClose(hBus);
  4208. continue;
  4209. }
  4210. p = (PWSTR) ((PUCHAR) ValueInfo + ValueInfo->DataOffset);
  4211. if (p[0] != L'A' || p[1] != L'P' || p[2] != L'M' || p[3] != 0) {
  4212. NtClose (hBus);
  4213. continue;
  4214. }
  4215. status = NtQueryValueKey(
  4216. hBus,
  4217. &ConfigName,
  4218. KeyValueFullInformation,
  4219. ValueInfo,
  4220. sizeof (buffer),
  4221. &junk
  4222. );
  4223. NtClose(hBus);
  4224. if (!NT_SUCCESS(status)) {
  4225. continue ;
  4226. }
  4227. Desc = (PCM_FULL_RESOURCE_DESCRIPTOR) ((PUCHAR)
  4228. ValueInfo + ValueInfo->DataOffset);
  4229. PDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)
  4230. Desc->PartialResourceList.PartialDescriptors);
  4231. if (PDesc->Type == CmResourceTypeDeviceSpecific) {
  4232. // got it..
  4233. ApmEntry = (PAPM_REGISTRY_INFO) (PDesc+1);
  4234. break;
  4235. }
  4236. }
  4237. NtClose(hMFunc);
  4238. if ( (ApmEntry->Signature[0] != 'A') ||
  4239. (ApmEntry->Signature[1] != 'P') ||
  4240. (ApmEntry->Signature[2] != 'M') )
  4241. {
  4242. return APM_NOT_PRESENT;
  4243. }
  4244. if (ApmEntry->Valid != 1) {
  4245. return APM_PRESENT_BUT_NOT_USABLE;
  4246. }
  4247. // --------------------------------------------------------------------
  4248. //
  4249. // Second Part - what sort of APM bios is it?
  4250. //
  4251. // --------------------------------------------------------------------
  4252. //
  4253. // If we get this far, then we think there is an APM bios present
  4254. // on the machine, and ntdetect thinks it's usable.
  4255. // This means we found it, and it has a version we like, and claims
  4256. // to support the interfaces we like.
  4257. // But we still don't know if its good, bad, or neutral.
  4258. // Find Out.
  4259. //
  4260. //
  4261. // The machine/bios good/bad list code will leave a flag in the
  4262. // registry for us to check to see if it is a known good or known bad
  4263. // apm bios.
  4264. //
  4265. RtlInitUnicodeString(&unicodeString, rgzGoodBadKey);
  4266. InitializeObjectAttributes(
  4267. &objectAttributes,
  4268. &unicodeString,
  4269. OBJ_CASE_INSENSITIVE,
  4270. NULL,
  4271. NULL
  4272. );
  4273. status = NtOpenKey(&hGoodBad, KEY_READ, &objectAttributes);
  4274. if (! NT_SUCCESS(status)) {
  4275. return APM_NEUTRAL;
  4276. }
  4277. RtlInitUnicodeString(&IdentName, rgzGoodBadValue);
  4278. pvpi = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
  4279. status = NtQueryValueKey(
  4280. hGoodBad,
  4281. &IdentName,
  4282. KeyValuePartialInformation,
  4283. pvpi,
  4284. sizeof(buffer),
  4285. &junk
  4286. );
  4287. NtClose(hGoodBad);
  4288. if ( (NT_SUCCESS(status)) &&
  4289. (pvpi->Type == REG_DWORD) &&
  4290. (pvpi->DataLength == sizeof(ULONG)) )
  4291. {
  4292. pdw = (PULONG)&(pvpi->Data[0]);
  4293. BiosType = *pdw;
  4294. } else {
  4295. return APM_NEUTRAL;
  4296. }
  4297. if (BiosType & APM_BIOS_KNOWN_GOOD) {
  4298. return APM_ON_GOOD_LIST;
  4299. } else if (BiosType & APM_BIOS_KNOWN_BAD) {
  4300. return APM_ON_BAD_LIST;
  4301. } else {
  4302. return APM_NEUTRAL;
  4303. }
  4304. }
  4305. BOOL
  4306. IsAcpiMachine(
  4307. VOID
  4308. )
  4309. /*++
  4310. Routine Description:
  4311. IsAcpiMachine reports whether the OS thinks this is an ACPI
  4312. machine or not.
  4313. Return Value:
  4314. FALSE - this is NOT an acpi machine
  4315. TRUE - this IS an acpi machine
  4316. --*/
  4317. {
  4318. UNICODE_STRING unicodeString;
  4319. OBJECT_ATTRIBUTES objectAttributes;
  4320. HANDLE hKey;
  4321. NTSTATUS status;
  4322. PKEY_VALUE_PARTIAL_INFORMATION pvpi;
  4323. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)+sizeof(DWORD)+1];
  4324. ULONG junk;
  4325. PULONG pdw;
  4326. ULONG start;
  4327. ChkPrintEx(("syssetup: IsAcpiMachine: entered\n"));
  4328. RtlInitUnicodeString(&unicodeString, rgzAcpiKey);
  4329. InitializeObjectAttributes(
  4330. &objectAttributes,
  4331. &unicodeString,
  4332. OBJ_CASE_INSENSITIVE,
  4333. NULL,
  4334. NULL
  4335. );
  4336. status = NtOpenKey(&hKey, KEY_READ, &objectAttributes);
  4337. if (!NT_SUCCESS(status)) {
  4338. ChkPrintEx(("syssetup: IsAcpiMachine: returning FALSE, no key\n"));
  4339. return FALSE;
  4340. }
  4341. RtlInitUnicodeString(&unicodeString, rgzAcpiCount);
  4342. pvpi = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
  4343. status = NtQueryValueKey(
  4344. hKey,
  4345. &unicodeString,
  4346. KeyValuePartialInformation,
  4347. pvpi,
  4348. sizeof(buffer),
  4349. &junk
  4350. );
  4351. if ( (NT_SUCCESS(status)) &&
  4352. (pvpi->Type == REG_DWORD) &&
  4353. (pvpi->DataLength == sizeof(ULONG)) )
  4354. {
  4355. pdw = (PULONG)&(pvpi->Data[0]);
  4356. if (*pdw) {
  4357. NtClose(hKey);
  4358. ChkPrintEx(("syssetup: IsAcpiMachine: returning TRUE\n"));
  4359. return TRUE;
  4360. }
  4361. }
  4362. NtClose(hKey);
  4363. ChkPrintEx(("syssetup: IsAcpiMachine: returning FALSE, no match\n"));
  4364. return FALSE;
  4365. }
  4366. BOOL
  4367. IsApmLegalHalMachine(
  4368. VOID
  4369. )
  4370. /*++
  4371. Routine Description:
  4372. IsApmLegalHalMachine reports whether setup claims to have
  4373. installed the standard halx86 Hal that APM requires to function.
  4374. Return Value:
  4375. TRUE - this IS an ApmLegalHal machine, apm install may proceed.
  4376. FALSE - this is NOT an ApmLegalHal machine, do not install APM.
  4377. --*/
  4378. {
  4379. UNICODE_STRING unicodeString;
  4380. OBJECT_ATTRIBUTES objectAttributes;
  4381. HANDLE hKey;
  4382. NTSTATUS status;
  4383. PKEY_VALUE_PARTIAL_INFORMATION pvpi;
  4384. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)+sizeof(DWORD)+1];
  4385. ULONG junk;
  4386. PULONG pdw;
  4387. ULONG start;
  4388. ChkPrintEx(("syssetup: IsApmLegalHalMAchine: entered\n"));
  4389. RtlInitUnicodeString(&unicodeString, rgzApmLegalHalKey);
  4390. InitializeObjectAttributes(
  4391. &objectAttributes,
  4392. &unicodeString,
  4393. OBJ_CASE_INSENSITIVE,
  4394. NULL,
  4395. NULL
  4396. );
  4397. status = NtOpenKey(&hKey, KEY_READ, &objectAttributes);
  4398. if (!NT_SUCCESS(status)) {
  4399. ChkPrintEx(("syssetup: IsApmLegalHalMAchine: returning FALSE, no key\n"));
  4400. return FALSE;
  4401. }
  4402. RtlInitUnicodeString(&unicodeString, rgzApmHalPresent);
  4403. pvpi = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
  4404. status = NtQueryValueKey(
  4405. hKey,
  4406. &unicodeString,
  4407. KeyValuePartialInformation,
  4408. pvpi,
  4409. sizeof(buffer),
  4410. &junk
  4411. );
  4412. if ( (NT_SUCCESS(status)) &&
  4413. (pvpi->Type == REG_DWORD) &&
  4414. (pvpi->DataLength == sizeof(ULONG)) )
  4415. {
  4416. pdw = (PULONG)&(pvpi->Data[0]);
  4417. if (*pdw == 1) {
  4418. NtClose(hKey);
  4419. ChkPrintEx(("syssetup: IsApmLegalHalMAchine: returning TRUE\n"));
  4420. return TRUE;
  4421. }
  4422. }
  4423. NtClose(hKey);
  4424. ChkPrintEx(("syssetup: IsApmLegalHalMAchine: returning FALSE, no match\n"));
  4425. return FALSE;
  4426. }
  4427. typedef
  4428. BOOL
  4429. (*PRESTART_DEVICE) (
  4430. IN HDEVINFO DeviceInfoSet,
  4431. IN PSP_DEVINFO_DATA DeviceInfoData
  4432. );
  4433. BOOL
  4434. IsUSBController(
  4435. IN HDEVINFO DeviceInfoSet,
  4436. IN PSP_DEVINFO_DATA DeviceInfoData
  4437. )
  4438. {
  4439. HKEY hKey;
  4440. TCHAR szController[] = TEXT("Controller");
  4441. DWORD dwType, dwSize;
  4442. BYTE data;
  4443. hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
  4444. DeviceInfoData,
  4445. DICS_FLAG_GLOBAL,
  4446. 0,
  4447. DIREG_DRV,
  4448. KEY_READ);
  4449. //
  4450. // Check for a REG_BINARY (1-byte) 'Controller' value entry set to 0.
  4451. //
  4452. dwSize = sizeof(data);
  4453. if (RegQueryValueEx(hKey,
  4454. szController,
  4455. NULL,
  4456. &dwType,
  4457. &data,
  4458. &dwSize) != ERROR_SUCCESS ||
  4459. dwSize != sizeof(BYTE) ||
  4460. dwType != REG_BINARY) {
  4461. data = 0;
  4462. }
  4463. RegCloseKey(hKey);
  4464. return data;
  4465. }
  4466. void
  4467. DeviceBayRestartDevices(
  4468. CONST GUID * Guid,
  4469. PRESTART_DEVICE RestartDevice
  4470. )
  4471. {
  4472. HDEVINFO hDevInfo;
  4473. SP_DEVINFO_DATA did;
  4474. SP_DEVINSTALL_PARAMS dip;
  4475. int i;
  4476. hDevInfo = SetupDiGetClassDevs(Guid, NULL, NULL, 0);
  4477. if (hDevInfo != INVALID_HANDLE_VALUE) {
  4478. ZeroMemory(&did, sizeof(SP_DEVINFO_DATA));
  4479. did.cbSize = sizeof(SP_DEVINFO_DATA);
  4480. for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &did); i++) {
  4481. if (!RestartDevice || RestartDevice(hDevInfo, &did)) {
  4482. //
  4483. // restart the controller so that the filter driver is in
  4484. // place
  4485. //
  4486. ZeroMemory(&dip, sizeof(SP_DEVINSTALL_PARAMS));
  4487. dip.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  4488. if (SetupDiGetDeviceInstallParams(hDevInfo, &did, &dip)) {
  4489. dip.Flags |= DI_PROPERTIES_CHANGE;
  4490. SetupDiSetDeviceInstallParams(hDevInfo, &did, &dip);
  4491. }
  4492. }
  4493. }
  4494. SetupDiDestroyDeviceInfoList(hDevInfo);
  4495. }
  4496. }
  4497. BOOLEAN
  4498. AddDeviceBayFilter(
  4499. HKEY ClassKey
  4500. )
  4501. {
  4502. DWORD dwType, dwSize;
  4503. ULONG res,
  4504. filterLength,
  4505. length;
  4506. BOOLEAN added = FALSE,
  4507. addFilter;
  4508. TCHAR szFilter[] = TEXT("dbfilter\0");
  4509. PTCHAR szCurrentFilter, szOffset, szUpperFilters;
  4510. filterLength = lstrlen(szFilter);
  4511. dwSize = 0;
  4512. res = RegQueryValueEx(ClassKey,
  4513. REGSTR_VAL_UPPERFILTERS,
  4514. NULL,
  4515. &dwType,
  4516. NULL,
  4517. &dwSize);
  4518. if (res == ERROR_FILE_NOT_FOUND || dwType != REG_MULTI_SZ) {
  4519. //
  4520. // Value isn't there,
  4521. //
  4522. RegSetValueEx(ClassKey,
  4523. REGSTR_VAL_UPPERFILTERS,
  4524. 0,
  4525. REG_MULTI_SZ,
  4526. (PBYTE) szFilter,
  4527. (filterLength + 2) * sizeof(TCHAR) );
  4528. added = TRUE;
  4529. }
  4530. else if (res == ERROR_SUCCESS) {
  4531. szUpperFilters = (PTCHAR)
  4532. LocalAlloc(LPTR, dwSize + (filterLength + 1) * sizeof(TCHAR));
  4533. if (!szUpperFilters)
  4534. return FALSE;
  4535. szOffset = szUpperFilters + filterLength + 1;
  4536. res = RegQueryValueEx(ClassKey,
  4537. REGSTR_VAL_UPPERFILTERS,
  4538. NULL,
  4539. &dwType,
  4540. (PBYTE) szOffset,
  4541. &dwSize);
  4542. if (res == ERROR_SUCCESS) {
  4543. addFilter = TRUE;
  4544. for (szCurrentFilter = szOffset; *szCurrentFilter; ) {
  4545. length = lstrlen(szCurrentFilter);
  4546. if (lstrcmpi(szFilter, szCurrentFilter) == 0) {
  4547. addFilter = FALSE;
  4548. break;
  4549. }
  4550. szCurrentFilter += (length + 1);
  4551. }
  4552. if (addFilter) {
  4553. length = (filterLength + 1) * sizeof(TCHAR);
  4554. memcpy(szUpperFilters, szFilter, length);
  4555. dwSize += length;
  4556. res = RegSetValueEx(ClassKey,
  4557. REGSTR_VAL_UPPERFILTERS,
  4558. 0,
  4559. REG_MULTI_SZ,
  4560. (PBYTE) szUpperFilters,
  4561. dwSize);
  4562. added = (res == ERROR_SUCCESS);
  4563. }
  4564. }
  4565. LocalFree(szUpperFilters);
  4566. }
  4567. return added;
  4568. }
  4569. DWORD
  4570. DeviceBayClassInstaller(
  4571. IN DI_FUNCTION InstallFunction,
  4572. IN HDEVINFO DeviceInfoSet,
  4573. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  4574. )
  4575. /*++
  4576. Routine Description:
  4577. This routine is the class installer function for storage volumes.
  4578. Arguments:
  4579. InstallFunction - Supplies the install function.
  4580. DeviceInfoSet - Supplies the device info set.
  4581. DeviceInfoData - Supplies the device info data.
  4582. Return Value:
  4583. If this function successfully completed the requested action, the return
  4584. value is NO_ERROR.
  4585. If the default behavior is to be performed for the requested action, the
  4586. return value is ERROR_DI_DO_DEFAULT.
  4587. If an error occurred while attempting to perform the requested action, a
  4588. Win32 error code is returned.
  4589. --*/
  4590. {
  4591. HKEY hKeyClass;
  4592. switch (InstallFunction) {
  4593. case DIF_INSTALLDEVICE:
  4594. if (!SetupDiInstallDevice(DeviceInfoSet, DeviceInfoData)) {
  4595. return GetLastError();
  4596. }
  4597. hKeyClass = SetupDiOpenClassRegKey(&GUID_DEVCLASS_USB, KEY_ALL_ACCESS);
  4598. if (hKeyClass != INVALID_HANDLE_VALUE) {
  4599. if (AddDeviceBayFilter(hKeyClass)) {
  4600. //
  4601. // Restart all the USB devices
  4602. //
  4603. DeviceBayRestartDevices(&GUID_DEVCLASS_USB,
  4604. IsUSBController);
  4605. }
  4606. RegCloseKey(hKeyClass);
  4607. }
  4608. hKeyClass = SetupDiOpenClassRegKey(&GUID_DEVCLASS_1394, KEY_ALL_ACCESS);
  4609. if (hKeyClass != INVALID_HANDLE_VALUE) {
  4610. if (AddDeviceBayFilter(hKeyClass)) {
  4611. //
  4612. // Restart all the 1394 controllers
  4613. //
  4614. DeviceBayRestartDevices(&GUID_DEVCLASS_1394, NULL);
  4615. }
  4616. RegCloseKey(hKeyClass);
  4617. }
  4618. //
  4619. // We might want to do something with the friendly name in the future...
  4620. //
  4621. return NO_ERROR;
  4622. }
  4623. return ERROR_DI_DO_DEFAULT;
  4624. }
  4625. DWORD
  4626. EisaUpHalCoInstaller(
  4627. IN DI_FUNCTION InstallFunction,
  4628. IN HDEVINFO DeviceInfoSet,
  4629. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
  4630. IN OUT PCOINSTALLER_CONTEXT_DATA Context
  4631. )
  4632. {
  4633. #ifdef _X86_
  4634. return PciHalCoInstaller(InstallFunction, DeviceInfoSet, DeviceInfoData, Context);
  4635. #else
  4636. return NO_ERROR;
  4637. #endif
  4638. }
  4639. DWORD
  4640. ComputerClassInstaller(
  4641. IN DI_FUNCTION InstallFunction,
  4642. IN HDEVINFO DeviceInfoSet,
  4643. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  4644. )
  4645. /*++
  4646. Routine Description:
  4647. This routine acts as the class installer for Computer class (HAL) devices.
  4648. Arguments:
  4649. InstallFunction - Specifies the device installer function code indicating
  4650. the action being performed.
  4651. DeviceInfoSet - Supplies a handle to the device information set being
  4652. acted upon by this install action.
  4653. DeviceInfoData - Optionally, supplies the address of a device information
  4654. element being acted upon by this install action.
  4655. Return Value:
  4656. If this function successfully completed the requested action, the return
  4657. value is NO_ERROR.
  4658. If the default behavior is to be performed for the requested action, the
  4659. return value is ERROR_DI_DO_DEFAULT.
  4660. If an error occurred while attempting to perform the requested action, a
  4661. Win32 error code is returned.
  4662. --*/
  4663. {
  4664. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  4665. switch(InstallFunction) {
  4666. case DIF_SELECTDEVICE:
  4667. DeviceInstallParams.cbSize = sizeof(DeviceInstallParams);
  4668. if (SetupDiGetDeviceInstallParams(DeviceInfoSet,
  4669. DeviceInfoData,
  4670. &DeviceInstallParams
  4671. )) {
  4672. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_FILTERSIMILARDRIVERS;
  4673. SetupDiSetDeviceInstallParams(DeviceInfoSet,
  4674. DeviceInfoData,
  4675. &DeviceInstallParams
  4676. );
  4677. }
  4678. //
  4679. // We are not returning an error here because we want to break out and
  4680. // return ERROR_DI_DO_DEFAULT.
  4681. //
  4682. break;
  4683. }
  4684. return ERROR_DI_DO_DEFAULT;
  4685. }