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.

630 lines
22 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. pnpdrivers.c
  5. Abstract:
  6. Process Update PnP Drivers section of WINBOM.INI
  7. Task performed will be:
  8. Author:
  9. Donald McNamara (donaldm) 5/11/2000
  10. Revision History:
  11. --*/
  12. #include "factoryp.h"
  13. #include <newdev.h> // UpdateDriverForPlugAndPlayDevices constants
  14. #define PNP_CREATE_PIPE_EVENT _T("PNP_Create_Pipe_Event")
  15. #define PNP_NO_INSTALL_EVENTS _T("PnP_No_Pending_Install_Events")
  16. #define PNP_EVENT_TIMEOUT 120000 // 2 minutes
  17. #define PNP_INSTALL_TIMEOUT 450000 // 7 1/2 minutes
  18. #define DIR_DEFAULT_ROOT _T("%SystemRoot%\\drivers")
  19. #define STR_FLOPPY _T("FLOPPY:\\")
  20. #define LEN_STR_FLOPPY ( AS(STR_FLOPPY) - 1 )
  21. #define STR_CDROM _T("CDROM:\\")
  22. #define LEN_STR_CDROM ( AS(STR_CDROM) - 1 )
  23. static HANDLE WaitForOpenEvent(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName, DWORD dwMilliseconds);
  24. BOOL StartPnP()
  25. {
  26. HANDLE hEvent;
  27. BOOL bRet = FALSE;
  28. // If we have already start PnP once, should not try to signal it again.
  29. //
  30. if ( GET_FLAG(g_dwFactoryFlags, FLAG_PNP_STARTED) )
  31. return TRUE;
  32. //
  33. // Signal the PNP_CREATE_PIPE_EVENT, with the UMPNPMGR is waiting on, so that
  34. // it can start processing installed devices.
  35. //
  36. // First we must wait till we can open the event, because if it doesn't already exist
  37. // then the PnP wont be listening to it when we signal it.
  38. //
  39. if ( hEvent = WaitForOpenEvent(EVENT_MODIFY_STATE, FALSE, PNP_CREATE_PIPE_EVENT, PNP_EVENT_TIMEOUT) )
  40. {
  41. // Signal the event now so that pnp starts up.
  42. //
  43. if ( !SetEvent(hEvent) )
  44. {
  45. // Unable to signal the event to tell pnp to start for some reason.
  46. //
  47. FacLogFile(0 | LOG_ERR, IDS_ERR_PNPSIGNALEVENT, GetLastError());
  48. }
  49. else
  50. {
  51. SET_FLAG(g_dwFactoryFlags, FLAG_PNP_STARTED);
  52. bRet = TRUE;
  53. }
  54. // We are done with this event.
  55. //
  56. CloseHandle(hEvent);
  57. }
  58. else
  59. {
  60. // Couldn't open up the event to tell pnp to get going.
  61. //
  62. FacLogFile(0 | LOG_ERR, IDS_ERR_PNPSTARTEVENT, GetLastError());
  63. }
  64. return bRet;
  65. }
  66. BOOL WaitForPnp(DWORD dwTimeOut)
  67. {
  68. HANDLE hEvent;
  69. BOOL bRet = TRUE;
  70. // If we have already waited once, should have to wait again
  71. // (at least I think that is right).
  72. //
  73. if ( GET_FLAG(g_dwFactoryFlags, FLAG_PNP_DONE) )
  74. return TRUE;
  75. //
  76. // Wait for the PnP_No_Pending_Install_Events event, with the UMPNPMGR signals when it is done.
  77. //
  78. // Try to open the pnp finished install event.
  79. //
  80. if ( hEvent = WaitForOpenEvent(SYNCHRONIZE, FALSE, PNP_NO_INSTALL_EVENTS, PNP_EVENT_TIMEOUT) )
  81. {
  82. DWORD dwError;
  83. // Lets wait for the event to be signaled that pnp is all done.
  84. //
  85. dwError = WaitForSingleObject(hEvent, dwTimeOut);
  86. if ( WAIT_OBJECT_0 != dwError )
  87. {
  88. // Waiting on the event failed for some reason.
  89. //
  90. FacLogFile(0 | LOG_ERR, IDS_ERR_PNPWAITFINISH, ( WAIT_FAILED == dwError ) ? GetLastError() : dwError);
  91. }
  92. else
  93. {
  94. // Woo hoo, looks like everything worked.
  95. //
  96. SET_FLAG(g_dwFactoryFlags, FLAG_PNP_DONE);
  97. bRet = TRUE;
  98. }
  99. // Make sure we close the event handle.
  100. //
  101. CloseHandle(hEvent);
  102. }
  103. else
  104. {
  105. // Couldn't open up the event to wait on.
  106. //
  107. FacLogFile(0 | LOG_ERR, IDS_ERR_PNPFINISHEVENT, GetLastError());
  108. }
  109. return bRet;
  110. }
  111. /*++
  112. ===============================================================================
  113. Routine Description:
  114. BOOL UpdateDrivers
  115. This routine will walk through the list of updated drivers presented in
  116. the WINBOM, and then copy all of the driver files for each one
  117. Arguments:
  118. lpStateData->lpszWinBOMPath
  119. - Path to the WinBOM file.
  120. Return Value:
  121. TRUE if all drivers files where copied
  122. FALSE if there was an error
  123. ===============================================================================
  124. --*/
  125. BOOL UpdateDrivers(LPSTATEDATA lpStateData)
  126. {
  127. BOOL bRet = TRUE;
  128. LPTSTR lpszWinBOMPath = lpStateData->lpszWinBOMPath,
  129. lpszDevicePath,
  130. lpszRootPath,
  131. lpszDefRoot,
  132. lpszDst,
  133. lpszSrc,
  134. lpszBuffer,
  135. lpszKey,
  136. lpszDontCare;
  137. TCHAR szDstPath[MAX_PATH],
  138. szSrcPath[MAX_PATH],
  139. szPathBuffer[MAX_PATH],
  140. szNetShare[MAX_PATH],
  141. cDriveLetter;
  142. DWORD dwKeyLen,
  143. cbDevicePath,
  144. dwDevicePathLen,
  145. dwOldSize;
  146. NET_API_STATUS nErr;
  147. // Get a buffer for the device paths. It will be either empty if they
  148. // don't have the optional additional paths key in the winbom.
  149. //
  150. if ( NULL == (lpszDevicePath = IniGetStringEx(lpszWinBOMPath, INI_SEC_WBOM_DRIVERUPDATE, INI_VAL_WBOM_DEVICEPATH, NULL, &cbDevicePath)) )
  151. {
  152. // We must have a buffer for the device path we will update in the registry.
  153. //
  154. cbDevicePath = 256;
  155. dwDevicePathLen = 0;
  156. if ( NULL == (lpszDevicePath = (LPTSTR) MALLOC(cbDevicePath * sizeof(TCHAR))) )
  157. {
  158. FacLogFile(0 | LOG_ERR, IDS_ERR_MEMORY, GetLastError());
  159. return FALSE;
  160. }
  161. }
  162. else
  163. {
  164. dwDevicePathLen = lstrlen(lpszDevicePath);
  165. }
  166. // Now get the optional root path for the drivers to be copied down.
  167. //
  168. lpszRootPath = IniGetString(lpszWinBOMPath, INI_SEC_WBOM_DRIVERUPDATE, INI_VAL_WBOM_PNP_DIR, NULL);
  169. // We have to have something for the root path even if the key isn't there.
  170. //
  171. lpszDefRoot = lpszRootPath ? lpszRootPath : DIR_DEFAULT_ROOT;
  172. // Try to get the whole driver section in the winbom.
  173. //
  174. lpszBuffer = IniGetSection(lpszWinBOMPath, INI_SEC_WBOM_DRIVERS);
  175. if ( lpszBuffer )
  176. {
  177. // Process all lines in this section. The format of the section is:
  178. //
  179. // source=destination
  180. //
  181. // The source can be any valid source path. If this path is a
  182. // UNC path, then we will connect to it. It can also start with
  183. // FLOPPY:\ or CDROM:\, with will be replace with the right drive
  184. // letter.
  185. //
  186. // The destination is the directory relative to target root that
  187. // we will use to copy the updated drivers into. It will be added,
  188. // along with any subdirs, to the device path in the registry.
  189. //
  190. for ( lpszKey = lpszBuffer; *lpszKey; lpszKey += dwKeyLen )
  191. {
  192. // Save the length of this string so we know where
  193. // the next key starts.
  194. //
  195. dwKeyLen = lstrlen(lpszKey) + 1;
  196. // Look for the value of the key after the = sign.
  197. //
  198. if ( lpszDst = StrChr(lpszKey, _T('=')) )
  199. {
  200. // Terminate the source where the = is, and then
  201. // make sure there is something after it for the
  202. // destination.
  203. //
  204. *lpszDst++ = NULLCHR;
  205. if ( NULLCHR == *lpszDst )
  206. {
  207. lpszDst = NULL;
  208. }
  209. }
  210. // We have to have a value to copy the driver.
  211. //
  212. if ( lpszDst )
  213. {
  214. //
  215. // At this level in the code (until a little bit later), set the destination
  216. // pointer to NULL to indicate an error. That will make it so we don't add
  217. // the path to the device path in the registry. It will also return a failure
  218. // for this state, but we will keep on going with the next key.
  219. //
  220. // Set the source root as the key name.
  221. //
  222. lpszSrc = lpszKey;
  223. // Create the expanded full path for the destination.
  224. //
  225. lstrcpyn(szDstPath, lpszDefRoot, AS(szDstPath));
  226. AddPathN(szDstPath, lpszDst, AS(szDstPath));
  227. ExpandFullPath(NULL, szDstPath, AS(szDstPath));
  228. // Make sure we have a destination to copy to before we continue.
  229. //
  230. if ( NULLCHR == szDstPath[0] )
  231. {
  232. // Log an error and set the destination pointer to NULL.
  233. //
  234. FacLogFile(0 | LOG_ERR, IDS_ERR_DSTBAD, lpszDst, GetLastError());
  235. lpszDst = NULL;
  236. }
  237. else
  238. {
  239. //
  240. // At this level in the code (disregard the above comment), set the
  241. // source pointer to NULL to indicate an error. That will make it so
  242. // we don't add the destination path to the device path in the registry
  243. // or try and copy any files to it. It will also return a failure for
  244. // this state, but we will keep on going with the next key.
  245. //
  246. // Determine if this is a UNC path. If it is not, then it is
  247. // assumed to be a local path.
  248. //
  249. szNetShare[0] = NULLCHR;
  250. if ( GetUncShare(lpszSrc, szNetShare, AS(szNetShare)) && szNetShare[0] )
  251. {
  252. // Connect to the UNC , using the supplied credentials.
  253. //
  254. if ( NERR_Success != (nErr = FactoryNetworkConnect(szNetShare, lpszWinBOMPath, INI_SEC_WBOM_DRIVERUPDATE, TRUE)) )
  255. {
  256. // Log an error and set the source pointer to NULL.
  257. //
  258. FacLogFile(0 | LOG_ERR, IDS_ERR_NETCONNECT, szNetShare, nErr);
  259. szNetShare[0] = NULLCHR;
  260. lpszSrc = NULL;
  261. }
  262. }
  263. else if ( ( lstrlen(lpszSrc) >= LEN_STR_FLOPPY ) &&
  264. ( CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, lpszSrc, LEN_STR_FLOPPY, STR_FLOPPY, LEN_STR_FLOPPY) == CSTR_EQUAL ) )
  265. {
  266. // Make sure there is a floppy drive in the system.
  267. //
  268. if ( NULLCHR == (cDriveLetter = GetDriveLetter(DRIVE_REMOVABLE)) )
  269. {
  270. // Log an error and set the source pointer to NULL.
  271. //
  272. FacLogFile(0 | LOG_ERR, IDS_ERR_FLOPPYNOTFOUND, lpszSrc);
  273. lpszSrc = NULL;
  274. }
  275. else
  276. {
  277. // Advance the source pointer to the character before the :\ and then
  278. // set that character to the driver letter returned for the floppy.
  279. //
  280. lpszSrc += LEN_STR_FLOPPY - 3;
  281. *lpszSrc = cDriveLetter;
  282. }
  283. }
  284. else if ( ( lstrlen(lpszSrc) >= LEN_STR_CDROM ) &&
  285. ( CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, lpszSrc, LEN_STR_CDROM, STR_CDROM, LEN_STR_CDROM) == CSTR_EQUAL ) )
  286. {
  287. // Make sure there is a CD-ROM drive in the system.
  288. //
  289. if ( NULLCHR == (cDriveLetter = GetDriveLetter(DRIVE_CDROM)) )
  290. {
  291. // Log an error and set the source pointer to NULL.
  292. //
  293. FacLogFile(0 | LOG_ERR, IDS_ERR_CDROMNOTFOUND, lpszSrc);
  294. lpszSrc = NULL;
  295. }
  296. else
  297. {
  298. // Advance the source pointer to the character before the :\ and then
  299. // set that character to the driver letter returned for the CD-ROM.
  300. //
  301. lpszSrc += LEN_STR_CDROM - 3;
  302. *lpszSrc = cDriveLetter;
  303. }
  304. }
  305. // If there is a source, expand it out.
  306. //
  307. if ( lpszSrc )
  308. {
  309. // Create the expanded full path for the source.
  310. //
  311. ExpandFullPath(lpszSrc, szSrcPath, AS(szSrcPath));
  312. // Make sure we have a source to copy to before we continue.
  313. //
  314. if ( NULLCHR == szSrcPath[0] )
  315. {
  316. // Log an error and set the source pointer to NULL.
  317. //
  318. FacLogFile(0 | LOG_ERR, IDS_ERR_SRCBAD, lpszSrc, GetLastError());
  319. lpszSrc = NULL;
  320. }
  321. else if ( !DirectoryExists(szSrcPath) || !CopyDirectory(szSrcPath, szDstPath) )
  322. {
  323. // Log an error and set the source pointer to NULL.
  324. //
  325. FacLogFile(0 | LOG_ERR, IDS_ERR_DRVCOPYFAILED, szSrcPath, szDstPath);
  326. lpszSrc = NULL;
  327. }
  328. }
  329. // Source will only be valid if we actually copied some drivers.
  330. //
  331. if ( NULL == lpszSrc )
  332. {
  333. // Set this so we don't add this path to the registry.
  334. //
  335. lpszDst = NULL;
  336. }
  337. // Clean up and drive mappings we may have done to a remote Server/Share.
  338. //
  339. if ( ( szNetShare[0] ) &&
  340. ( NERR_Success != (nErr = FactoryNetworkConnect(szNetShare, lpszWinBOMPath, NULL, FALSE)) ) )
  341. {
  342. // Log a warning.
  343. //
  344. FacLogFile(2, IDS_WRN_NETDISCONNECT, szNetShare, nErr);
  345. }
  346. }
  347. // Now if the destination pointer is NULL, we know we need to
  348. // return an error for this state.
  349. //
  350. if ( NULL == lpszDst )
  351. {
  352. bRet = FALSE;
  353. }
  354. }
  355. else
  356. {
  357. // If there was no =, then just use the key part
  358. // as the dest and add it to the device path.
  359. //
  360. lpszDst = lpszKey;
  361. }
  362. // Now if we have something to add to our device path,
  363. // add it now.
  364. //
  365. if ( lpszDst )
  366. {
  367. // Make sure our buffer is still big enough.
  368. // The two extra are for the possible semi-colon
  369. // we might add and one more to be safe. We
  370. // don't have to worry about the null terminator
  371. // because we do less than or equal to our current
  372. // buffer size.
  373. //
  374. dwOldSize = cbDevicePath;
  375. dwDevicePathLen += lstrlen(lpszDst);
  376. while ( cbDevicePath <= (dwDevicePathLen + 2) )
  377. {
  378. cbDevicePath *= 2;
  379. }
  380. // Make sure we still have a buffer.
  381. //
  382. if ( cbDevicePath > dwOldSize )
  383. {
  384. LPTSTR lpszTmpDevicePath = (LPTSTR) REALLOC(lpszDevicePath, cbDevicePath * sizeof(TCHAR));
  385. if ( NULL == lpszTmpDevicePath )
  386. {
  387. // If this realloc fails, we just need to bail.
  388. //
  389. FREE(lpszDevicePath);
  390. FREE(lpszRootPath);
  391. FREE(lpszBuffer);
  392. FacLogFile(0 | LOG_ERR, IDS_ERR_MEMORY, GetLastError());
  393. return FALSE;
  394. }
  395. else
  396. {
  397. lpszDevicePath = lpszTmpDevicePath;
  398. }
  399. }
  400. // If we already have added a path, tack on a semicolon.
  401. //
  402. if ( *lpszDevicePath )
  403. {
  404. if ( FAILED ( StringCchCat ( lpszDevicePath, cbDevicePath, _T(";") ) ) )
  405. {
  406. FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), lpszDevicePath, _T(";") );
  407. }
  408. dwDevicePathLen++;
  409. }
  410. // Now add our path.
  411. //
  412. if ( FAILED ( StringCchCat ( lpszDevicePath, cbDevicePath, lpszDst) ) )
  413. {
  414. FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), lpszDevicePath, lpszDst ) ;
  415. }
  416. }
  417. }
  418. FREE(lpszBuffer);
  419. }
  420. // If we are saving this list to the registry, then
  421. // we need to add to our buffer.
  422. //
  423. if ( *lpszDevicePath &&
  424. !UpdateDevicePath(lpszDevicePath, lpszDefRoot, TRUE) )
  425. {
  426. FacLogFile(0 | LOG_ERR, IDS_ERR_UPDATEDEVICEPATH, lpszDevicePath);
  427. bRet = FALSE;
  428. }
  429. // Clean up any memory (macro checks for NULL).
  430. //
  431. FREE(lpszRootPath);
  432. FREE(lpszDevicePath);
  433. return bRet;
  434. }
  435. BOOL DisplayUpdateDrivers(LPSTATEDATA lpStateData)
  436. {
  437. return ( IniSettingExists(lpStateData->lpszWinBOMPath, INI_SEC_WBOM_DRIVERS, NULL, NULL) ||
  438. IniSettingExists(lpStateData->lpszWinBOMPath, INI_SEC_WBOM_DRIVERUPDATE, INI_VAL_WBOM_DEVICEPATH, NULL) );
  439. }
  440. BOOL InstallDrivers(LPSTATEDATA lpStateData)
  441. {
  442. // Should always let normal pnp finish before we start
  443. // enumerating all the devices checking for updated drivers.
  444. //
  445. WaitForPnp(PNP_INSTALL_TIMEOUT);
  446. // Make sure we want to do this.
  447. //
  448. if ( !DisplayInstallDrivers(lpStateData) )
  449. {
  450. return TRUE;
  451. }
  452. return UpdatePnpDeviceDrivers();
  453. }
  454. BOOL DisplayInstallDrivers(LPSTATEDATA lpStateData)
  455. {
  456. return ( ( IniSettingExists(lpStateData->lpszWinBOMPath, INI_SEC_WBOM_DRIVERUPDATE, INI_KEY_WBOM_INSTALLDRIVERS, INI_VAL_WBOM_YES) ) ||
  457. ( !GET_FLAG(g_dwFactoryFlags, FLAG_OOBE) &&
  458. IniSettingExists(lpStateData->lpszWinBOMPath, INI_SEC_WBOM_DRIVERS, NULL, NULL) ) );
  459. }
  460. BOOL NormalPnP(LPSTATEDATA lpStateData)
  461. {
  462. return StartPnP();
  463. }
  464. BOOL WaitPnP(LPSTATEDATA lpStateData)
  465. {
  466. // If this is the extra wait state, we only
  467. // do it if there is a certain key in the winbom.
  468. //
  469. if ( DisplayWaitPnP(lpStateData) )
  470. {
  471. return WaitForPnp(PNP_INSTALL_TIMEOUT);
  472. }
  473. return TRUE;
  474. }
  475. BOOL DisplayWaitPnP(LPSTATEDATA lpStateData)
  476. {
  477. BOOL bRet = IniSettingExists(lpStateData->lpszWinBOMPath, INI_SEC_WBOM_DRIVERUPDATE, INI_KEY_WBOM_PNPWAIT, INI_VAL_WBOM_YES);
  478. if ( stateWaitPnP == lpStateData->state )
  479. {
  480. bRet = !bRet;
  481. }
  482. return bRet;
  483. }
  484. BOOL SetDisplay(LPSTATEDATA lpStateData)
  485. {
  486. // If this is the second set display, only bother if we
  487. // re-enumerated the installed drivers.
  488. //
  489. if ( ( stateSetDisplay2 == lpStateData->state ) &&
  490. ( !DisplayInstallDrivers(lpStateData) ) )
  491. {
  492. return TRUE;
  493. }
  494. // Call the syssetup function to reset the display.
  495. //
  496. return SetupSetDisplay(lpStateData->lpszWinBOMPath,
  497. WBOM_SETTINGS_SECTION,
  498. WBOM_SETTINGS_DISPLAY,
  499. WBOM_SETTINGS_REFRESH,
  500. WBOM_SETTINGS_DISPLAY_MINWIDTH,
  501. WBOM_SETTINGS_DISPLAY_MINHEIGHT,
  502. WBOM_SETTINGS_DISPLAY_MINDEPTH);
  503. }
  504. static HANDLE WaitForOpenEvent(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName, DWORD dwMilliseconds)
  505. {
  506. HANDLE hEvent;
  507. DWORD dwTime = 0,
  508. dwSleep = 100;
  509. BOOL bBail = (0 == dwMilliseconds);
  510. // Keep looping until we get an event handle or we time out.
  511. //
  512. while ( ( NULL == (hEvent = OpenEvent(dwDesiredAccess, bInheritHandle, lpName)) ) && !bBail )
  513. {
  514. // Only bother to test for the time out if they didn't
  515. // pass in infinite.
  516. //
  517. if ( INFINITE != dwMilliseconds )
  518. {
  519. // Add our sleep interval and make sure we will not
  520. // go over out limit.
  521. //
  522. dwTime += dwSleep;
  523. if ( dwTime >= dwMilliseconds )
  524. {
  525. // If we will go over, caclculate how much
  526. // time we have left to sleep (it must be less
  527. // than our normal interval) and set the flag
  528. // so we stop trying after the next try.
  529. //
  530. dwSleep = dwMilliseconds - (dwTime - dwSleep);
  531. bBail = TRUE;
  532. }
  533. }
  534. // Now sleep for our interval or less (should never
  535. // be zero, but doesn't really matter if it is).
  536. //
  537. Sleep(dwSleep);
  538. }
  539. // If we are failing and we timed out, we need to set
  540. // the last error (if we didn't time out the error will
  541. // already be set by OpenEvent).
  542. //
  543. if ( ( NULL == hEvent ) && bBail )
  544. SetLastError(WAIT_TIMEOUT);
  545. // Return the event handle.
  546. //
  547. return hEvent;
  548. }