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.

2691 lines
76 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. TapeDrive
  8. SCSIAdapter
  9. CdromDrive
  10. Author:
  11. Lonny McMichael 26-February-1996
  12. --*/
  13. #include "setupp.h"
  14. #pragma hdrstop
  15. //
  16. // include common INF strings headerfile.
  17. //
  18. #include <infstr.h>
  19. //
  20. // instantiate device class GUIDs.
  21. //
  22. #include <initguid.h>
  23. #include <devguid.h>
  24. #include <ntddvol.h>
  25. #include <ntddscsi.h> // for StorageCdromQueryCdda()
  26. #include <ntddcdrm.h> // for StorageCdromQueryCdda()
  27. #define _NTSCSI_USER_MODE_ // prevents all the kernel-mode stuff
  28. #include <scsi.h> // for StorageCdromQueryCdda()
  29. ULONG BreakWhenGettingModePage2A = FALSE;
  30. #ifdef UNICODE
  31. #define _UNICODE
  32. #endif
  33. #include <tchar.h>
  34. #define TCHAR_NULL TEXT('\0')
  35. //
  36. // Just to make sure no one is trying to use this obsolete string definition.
  37. //
  38. #ifdef IDS_DEVINSTALL_ERROR
  39. #undef IDS_DEVINSTALL_ERROR
  40. #endif
  41. #if (_X86_)
  42. #define DISABLE_IMAPI 0
  43. #else
  44. #define DISABLE_IMAPI 1
  45. #endif
  46. //
  47. // Define the location of the device settings tree.
  48. //
  49. #define STORAGE_DEVICE_SETTINGS_DATABASE TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Storage\\DeviceSettings\\")
  50. #define REDBOOK_SETTINGS_KEY TEXT("DigitalAudio")
  51. #define REDBOOK_SERVICE_NAME TEXT("redbook")
  52. #define IMAPI_SETTINGS_KEY TEXT("Imapi")
  53. #define IMAPI_ENABLE_VALUE TEXT("EnableImapi")
  54. #define IMAPI_SERVICE_NAME TEXT("imapi")
  55. typedef struct STORAGE_COINSTALLER_CONTEXT {
  56. PWSTR DeviceDescBuffer;
  57. HANDLE DeviceEnumKey;
  58. union {
  59. struct {
  60. BOOLEAN RedbookInstalled;
  61. BOOLEAN ImapiInstalled;
  62. } CdRom;
  63. };
  64. } STORAGE_COINSTALLER_CONTEXT, *PSTORAGE_COINSTALLER_CONTEXT;
  65. typedef struct _PASS_THROUGH_REQUEST {
  66. SCSI_PASS_THROUGH Srb;
  67. SENSE_DATA SenseInfoBuffer;
  68. UCHAR DataBuffer[0];
  69. } PASS_THROUGH_REQUEST, *PPASS_THROUGH_REQUEST;
  70. #define PASS_THROUGH_NOT_READY_RETRY_INTERVAL 100
  71. //
  72. // Some debugging aids for us kernel types
  73. //
  74. #define CHKPRINT 0
  75. #if CHKPRINT
  76. #define ChkPrintEx(_x_) DbgPrint _x_ // use: ChkPrintEx(( "%x", var, ... ));
  77. #define ChkBreak() DbgBreakPoint()
  78. #else
  79. #define ChkPrintEx(_x_)
  80. #define ChkBreak()
  81. #endif
  82. DWORD StorageForceRedbookOnInaccurateDrives = FALSE;
  83. BOOLEAN
  84. OverrideFriendlyNameForTape(
  85. IN HDEVINFO DeviceInfoSet,
  86. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  87. );
  88. DWORD
  89. RegCopyKey(
  90. HKEY SourceKey,
  91. HKEY DestinationKey
  92. );
  93. BOOLEAN
  94. StorageCopyDeviceSettings(
  95. IN HDEVINFO DeviceInfo,
  96. IN PSP_DEVINFO_DATA DeviceInfoData,
  97. IN HKEY DeviceEnumKey
  98. );
  99. VOID
  100. StorageInstallCdrom(
  101. IN HDEVINFO DeviceInfo,
  102. IN PSP_DEVINFO_DATA DeviceInfoData,
  103. IN HANDLE DeviceEnumKey,
  104. IN BOOLEAN PreInstall
  105. );
  106. BOOLEAN
  107. StorageUpdateRedbookSettings(
  108. IN HDEVINFO DeviceInfo,
  109. IN PSP_DEVINFO_DATA DeviceInfoData,
  110. IN HKEY DeviceEnumKey,
  111. IN PCDVD_CAPABILITIES_PAGE DeviceCapabilities OPTIONAL
  112. );
  113. BOOLEAN
  114. StorageUpdateImapiSettings(
  115. IN HDEVINFO DeviceInfo,
  116. IN PSP_DEVINFO_DATA DeviceInfoData,
  117. IN HKEY DeviceEnumKey,
  118. IN PCDVD_CAPABILITIES_PAGE DeviceCapabilities OPTIONAL
  119. );
  120. DWORD
  121. StorageInstallFilter(
  122. IN HDEVINFO DeviceInfo,
  123. IN PSP_DEVINFO_DATA DeviceInfoData,
  124. IN LPTSTR FilterName,
  125. IN DWORD FilterType
  126. );
  127. DWORD
  128. SetServiceStart(
  129. IN LPCTSTR ServiceName,
  130. IN DWORD StartType,
  131. OUT DWORD *OldStartType
  132. );
  133. DWORD
  134. AddFilterDriver(
  135. IN HDEVINFO DeviceInfo,
  136. IN PSP_DEVINFO_DATA DeviceInfoData,
  137. IN LPTSTR ServiceName,
  138. IN DWORD FilterType
  139. );
  140. VOID
  141. StorageInterpretSenseInfo(
  142. IN PSENSE_DATA SenseData,
  143. IN UCHAR SenseDataSize,
  144. OUT PDWORD ErrorValue, // from WinError.h
  145. OUT PBOOLEAN SuggestRetry OPTIONAL,
  146. OUT PDWORD SuggestRetryDelay OPTIONAL
  147. );
  148. typedef struct _STORAGE_REDBOOK_SETTINGS {
  149. ULONG CDDASupported;
  150. ULONG CDDAAccurate;
  151. ULONG ReadSizesSupported;
  152. } STORAGE_REDBOOK_SETTINGS, *PSTORAGE_REDBOOK_SETTINGS;
  153. #if 0
  154. #define BREAK ASSERT(!"Break")
  155. #else
  156. #define BREAK
  157. #endif
  158. DWORD
  159. TapeClassInstaller(
  160. IN DI_FUNCTION InstallFunction,
  161. IN HDEVINFO DeviceInfoSet,
  162. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  163. )
  164. /*++
  165. Routine Description:
  166. This routine acts as the class installer for TapeDrive devices. Now that
  167. we've stopped supporting legacy INFs, it presently does nothing! :-)
  168. Arguments:
  169. InstallFunction - Specifies the device installer function code indicating
  170. the action being performed.
  171. DeviceInfoSet - Supplies a handle to the device information set being
  172. acted upon by this install action.
  173. DeviceInfoData - Optionally, supplies the address of a device information
  174. element being acted upon by this install action.
  175. Return Value:
  176. If this function successfully completed the requested action, the return
  177. value is NO_ERROR.
  178. If the default behavior is to be performed for the requested action, the
  179. return value is ERROR_DI_DO_DEFAULT.
  180. If an error occurred while attempting to perform the requested action, a
  181. Win32 error code is returned.
  182. --*/
  183. {
  184. switch(InstallFunction) {
  185. default :
  186. //
  187. // Just do the default action.
  188. //
  189. return ERROR_DI_DO_DEFAULT;
  190. }
  191. }
  192. DWORD
  193. ScsiClassInstaller(
  194. IN DI_FUNCTION InstallFunction,
  195. IN HDEVINFO DeviceInfoSet,
  196. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  197. )
  198. /*++
  199. Routine Description:
  200. This routine acts as the class installer for SCSIAdapter devices. It
  201. provides special handling for the following DeviceInstaller function codes:
  202. DIF_ALLOW_INSTALL - Check to see if the selected driver node supports NT
  203. Arguments:
  204. InstallFunction - Specifies the device installer function code indicating
  205. the action being performed.
  206. DeviceInfoSet - Supplies a handle to the device information set being
  207. acted upon by this install action.
  208. DeviceInfoData - Optionally, supplies the address of a device information
  209. element being acted upon by this install action.
  210. Return Value:
  211. If this function successfully completed the requested action, the return
  212. value is NO_ERROR.
  213. If the default behavior is to be performed for the requested action, the
  214. return value is ERROR_DI_DO_DEFAULT.
  215. If an error occurred while attempting to perform the requested action, a
  216. Win32 error code is returned.
  217. --*/
  218. {
  219. switch(InstallFunction) {
  220. case DIF_ALLOW_INSTALL :
  221. //
  222. // Check to make sure the selected driver node supports NT.
  223. //
  224. if (DriverNodeSupportsNT(DeviceInfoSet, DeviceInfoData)) {
  225. return NO_ERROR;
  226. } else {
  227. SetupDebugPrint(L"A SCSI driver is not a Win NTdriver.\n");
  228. return ERROR_NON_WINDOWS_NT_DRIVER;
  229. }
  230. default :
  231. //
  232. // Just do the default action.
  233. //
  234. return ERROR_DI_DO_DEFAULT;
  235. }
  236. }
  237. DWORD
  238. HdcClassInstaller(
  239. IN DI_FUNCTION InstallFunction,
  240. IN HDEVINFO DeviceInfoSet,
  241. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  242. )
  243. /*++
  244. Routine Description:
  245. This routine acts as the class installer for hard disk controllers
  246. (IDE controllers/channels). It provides special handling for the
  247. following DeviceInstaller function codes:
  248. DIF_FIRSTTIMESETUP - Search through all root-enumerated devnodes, looking
  249. for ones being controlled by hdc-class drivers. Add
  250. any such devices found into the supplied device
  251. information set.
  252. Arguments:
  253. InstallFunction - Specifies the device installer function code indicating
  254. the action being performed.
  255. DeviceInfoSet - Supplies a handle to the device information set being
  256. acted upon by this install action.
  257. DeviceInfoData - Optionally, supplies the address of a device information
  258. element being acted upon by this install action.
  259. Return Value:
  260. If this function successfully completed the requested action, the return
  261. value is NO_ERROR.
  262. If the default behavior is to be performed for the requested action, the
  263. return value is ERROR_DI_DO_DEFAULT.
  264. If an error occurred while attempting to perform the requested action, a
  265. Win32 error code is returned.
  266. --*/
  267. {
  268. switch(InstallFunction) {
  269. case DIF_FIRSTTIMESETUP :
  270. //
  271. // BUGBUG (lonnym): handle this!
  272. //
  273. default :
  274. //
  275. // Just do the default action.
  276. //
  277. return ERROR_DI_DO_DEFAULT;
  278. }
  279. }
  280. BOOLEAN
  281. StorageGetCDVDCapabilities(
  282. IN HDEVINFO DeviceInfo,
  283. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
  284. IN OUT PCDVD_CAPABILITIES_PAGE CapabilitiesPage
  285. )
  286. {
  287. PPASS_THROUGH_REQUEST passThrough;
  288. PCDVD_CAPABILITIES_PAGE modePage;
  289. DWORD allocLength;
  290. DWORD dataLength;
  291. ULONG attempt;
  292. BOOLEAN status = FALSE;
  293. HANDLE deviceHandle;
  294. deviceHandle = INVALID_HANDLE_VALUE;
  295. passThrough = NULL;
  296. modePage = NULL;
  297. ASSERT(CapabilitiesPage != NULL);
  298. if (BreakWhenGettingModePage2A) {
  299. ChkPrintEx(("CDGetCap => entering\n"));
  300. DbgBreakPoint();
  301. }
  302. //
  303. // open a handle to the device, needed to send the ioctls
  304. //
  305. deviceHandle = UtilpGetDeviceHandle(DeviceInfo,
  306. DeviceInfoData,
  307. (LPGUID)&CdRomClassGuid,
  308. GENERIC_READ | GENERIC_WRITE
  309. );
  310. if (deviceHandle == INVALID_HANDLE_VALUE) {
  311. ChkPrintEx(("CDGetCap => cannot get device handle\n"));
  312. goto cleanup;
  313. }
  314. //
  315. // determine size of allocation needed
  316. //
  317. dataLength =
  318. sizeof(MODE_PARAMETER_HEADER10) + // larger of 6/10 byte
  319. sizeof(CDVD_CAPABILITIES_PAGE) + // the actual mode page
  320. 8; // extra spooge for drives that ignore DBD
  321. allocLength = sizeof(PASS_THROUGH_REQUEST) + dataLength;
  322. //
  323. // allocate this buffer for the ioctls
  324. //
  325. passThrough = (PPASS_THROUGH_REQUEST)MyMalloc(allocLength);
  326. if (passThrough == NULL) {
  327. ChkPrintEx(("CDGetCap => could not allocate for passThrough\n"));
  328. goto cleanup;
  329. }
  330. ASSERT(dataLength <= 0xff); // one char
  331. //
  332. // send 6-byte, then 10-byte if 6-byte failed.
  333. // then, just parse the information
  334. //
  335. for (attempt = 1; attempt <= 2; attempt++) {
  336. ULONG j;
  337. BOOLEAN retry = TRUE;
  338. DWORD error;
  339. for (j=0; (j < 5) && (retry); j++) {
  340. PSCSI_PASS_THROUGH srb = &passThrough->Srb;
  341. PCDB cdb = (PCDB)(&srb->Cdb[0]);
  342. DWORD bytes;
  343. BOOL b;
  344. retry = FALSE;
  345. ZeroMemory(passThrough, allocLength);
  346. srb->TimeOutValue = 20;
  347. srb->Length = sizeof(SCSI_PASS_THROUGH);
  348. srb->SenseInfoLength = sizeof(SENSE_DATA);
  349. srb->SenseInfoOffset =
  350. FIELD_OFFSET(PASS_THROUGH_REQUEST, SenseInfoBuffer);
  351. srb->DataBufferOffset =
  352. FIELD_OFFSET(PASS_THROUGH_REQUEST, DataBuffer);
  353. srb->DataIn = SCSI_IOCTL_DATA_IN;
  354. srb->DataTransferLength = dataLength;
  355. if ((attempt % 2) == 1) { // settings based on 6-byte request
  356. srb->CdbLength = 6;
  357. cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
  358. cdb->MODE_SENSE.PageCode = MODE_PAGE_CAPABILITIES;
  359. cdb->MODE_SENSE.AllocationLength = (UCHAR)dataLength;
  360. cdb->MODE_SENSE.Dbd = 1;
  361. } else { // settings based on 10 bytes request
  362. srb->CdbLength = 10;
  363. cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  364. cdb->MODE_SENSE10.PageCode = MODE_PAGE_CAPABILITIES;
  365. cdb->MODE_SENSE10.AllocationLength[0] = 0;
  366. cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(dataLength & 0xff);
  367. cdb->MODE_SENSE10.Dbd = 1;
  368. }
  369. //
  370. // buffers are all set, send the ioctl
  371. //
  372. b = DeviceIoControl(deviceHandle,
  373. IOCTL_SCSI_PASS_THROUGH,
  374. passThrough,
  375. allocLength,
  376. passThrough,
  377. allocLength,
  378. &bytes,
  379. NULL);
  380. if (!b) {
  381. ChkPrintEx(("CDGetCap => %s byte command failed to be sent to device\n",
  382. ((attempt%2) ? "6" : "10")
  383. ));
  384. retry = FALSE;
  385. continue; // try the next 'j' loop.
  386. }
  387. //
  388. // now see if we should retry
  389. //
  390. StorageInterpretSenseInfo(&passThrough->SenseInfoBuffer,
  391. SENSE_BUFFER_SIZE,
  392. &error,
  393. &retry,
  394. NULL);
  395. if (error != ERROR_SUCCESS) {
  396. ChkPrintEx(("CDGetCap => %s byte command failed (%x/%x/%x),"
  397. "%s retrying\n",
  398. ((attempt%2) ? "6" : "10"),
  399. passThrough->SenseInfoBuffer.SenseKey,
  400. passThrough->SenseInfoBuffer.AdditionalSenseCode,
  401. passThrough->SenseInfoBuffer.AdditionalSenseCodeQualifier,
  402. (retry ? "" : "not")
  403. ));
  404. //
  405. // retry will be set to either true or false to
  406. // have this loop (j) re-run or not....
  407. //
  408. continue;
  409. }
  410. //
  411. // else it worked!
  412. //
  413. ASSERT(retry == FALSE);
  414. retry = FALSE;
  415. ASSERT(status == FALSE);
  416. status = TRUE;
  417. }
  418. //
  419. // if unable to retrieve the page, just start the next loop.
  420. //
  421. if (!status) {
  422. continue; // try the next 'attempt' loop.
  423. }
  424. //
  425. // find the mode page data
  426. //
  427. // NOTE: if the drive fails to ignore the DBD bit,
  428. // we still need to install? HCT will catch this,
  429. // but legacy drives need it.
  430. //
  431. (ULONG_PTR)modePage = (ULONG_PTR)passThrough->DataBuffer;
  432. if (attempt == 1) {
  433. PMODE_PARAMETER_HEADER h;
  434. h = (PMODE_PARAMETER_HEADER)passThrough->DataBuffer;
  435. //
  436. // add the size of the header
  437. //
  438. (ULONG_PTR)modePage += sizeof(MODE_PARAMETER_HEADER);
  439. dataLength -= sizeof(MODE_PARAMETER_HEADER);
  440. //
  441. // add the size of the block descriptor, which should
  442. // always be zero, but isn't on some poorly behaved drives
  443. //
  444. if (h->BlockDescriptorLength) {
  445. ASSERT(h->BlockDescriptorLength == 8);
  446. ChkPrintEx(("CDGetCap => %s byte command ignored DBD bit (%x)\n",
  447. ((attempt%2) ? "6" : "10"),
  448. h->BlockDescriptorLength
  449. ));
  450. (ULONG_PTR)modePage += h->BlockDescriptorLength;
  451. dataLength -= h->BlockDescriptorLength;
  452. }
  453. } else {
  454. PMODE_PARAMETER_HEADER10 h;
  455. h = (PMODE_PARAMETER_HEADER10)passThrough->DataBuffer;
  456. //
  457. // add the size of the header
  458. //
  459. (ULONG_PTR)modePage += sizeof(MODE_PARAMETER_HEADER10);
  460. dataLength -= sizeof(MODE_PARAMETER_HEADER10);
  461. //
  462. // add the size of the block descriptor, which should
  463. // always be zero, but isn't on some poorly behaved drives
  464. //
  465. if ((h->BlockDescriptorLength[0] != 0) ||
  466. (h->BlockDescriptorLength[1] != 0)
  467. ) {
  468. ULONG_PTR bdLength = 0;
  469. bdLength += ((h->BlockDescriptorLength[0]) << 8);
  470. bdLength += ((h->BlockDescriptorLength[1]) & 0xff);
  471. ASSERT(bdLength == 8);
  472. ChkPrintEx(("CDGetCap => %s byte command ignored DBD bit (%x)\n",
  473. ((attempt%2) ? "6" : "10"),
  474. bdLength
  475. ));
  476. (ULONG_PTR)modePage += bdLength;
  477. dataLength -= (DWORD)bdLength;
  478. }
  479. }
  480. //
  481. // now have the pointer to the mode page data and length of usable data
  482. // copy it back to requestor's buffer
  483. //
  484. ChkPrintEx(("CDGetCap => %s byte command succeeded\n",
  485. (attempt%2) ? "6" : "10"));
  486. RtlZeroMemory(CapabilitiesPage, sizeof(CDVD_CAPABILITIES_PAGE));
  487. RtlCopyMemory(CapabilitiesPage,
  488. modePage,
  489. min(dataLength, sizeof(CDVD_CAPABILITIES_PAGE))
  490. );
  491. if (BreakWhenGettingModePage2A) {
  492. ChkPrintEx(("CDGetCap => Capabilities @ %#p\n", CapabilitiesPage));
  493. DbgBreakPoint();
  494. }
  495. goto cleanup; // no need to send another command
  496. }
  497. ChkPrintEx(("CDGetCap => Unable to get drive capabilities via modepage\n"));
  498. cleanup:
  499. if (passThrough) {
  500. MyFree(passThrough);
  501. }
  502. if (deviceHandle != INVALID_HANDLE_VALUE) {
  503. CloseHandle(deviceHandle);
  504. }
  505. return status;
  506. }
  507. BOOLEAN
  508. ScReadRegDword(
  509. IN HANDLE Key,
  510. IN LPTSTR ValueName,
  511. OUT PDWORD Value
  512. )
  513. {
  514. DWORD type;
  515. DWORD size = sizeof(DWORD);
  516. DWORD value;
  517. DWORD result;
  518. result = RegQueryValueEx(Key,
  519. ValueName,
  520. NULL,
  521. &type,
  522. (LPBYTE) &value,
  523. &size);
  524. if(result == ERROR_SUCCESS) {
  525. *Value = value;
  526. return TRUE;
  527. }
  528. return FALSE;
  529. }
  530. VOID
  531. StorageReadRedbookSettings(
  532. IN HANDLE Key,
  533. OUT STORAGE_REDBOOK_SETTINGS *Settings
  534. )
  535. {
  536. STORAGE_REDBOOK_SETTINGS settings;
  537. //
  538. // since this key exists, query for the values
  539. //
  540. DWORD dataType;
  541. DWORD dataSize;
  542. DWORD value;
  543. LONG results;
  544. settings.CDDASupported = FALSE;
  545. settings.CDDAAccurate = FALSE;
  546. settings.ReadSizesSupported = 0;
  547. if(ScReadRegDword(Key, TEXT("CDDASupported"), &value)) {
  548. settings.CDDASupported = value ? 1 : 0;
  549. }
  550. if(ScReadRegDword(Key, TEXT("CDDAAccurate"), &value)) {
  551. settings.CDDAAccurate = value ? 1 : 0;
  552. }
  553. if(ScReadRegDword(Key, TEXT("ReadSizesSupported"), &value)) {
  554. settings.ReadSizesSupported = value;
  555. }
  556. //
  557. // one of the three worked
  558. //
  559. ChkPrintEx(("StorageReadSettings: Query Succeeded:\n"));
  560. ChkPrintEx(("StorageReadSettings: ReadSizeMask (pre): %x\n",
  561. settings.ReadSizesSupported));
  562. ChkPrintEx(("StorageReadSettings: CDDAAccurate (pre): %x\n",
  563. settings.CDDAAccurate));
  564. ChkPrintEx(("StorageReadSettings: CDDASupported (pre): %x\n",
  565. settings.CDDASupported));
  566. //
  567. // interpret the redbook device settings.
  568. //
  569. if (settings.ReadSizesSupported) {
  570. ChkPrintEx(("StorageSeed: Drive supported only some sizes "
  571. " (%#08x)\n", settings.ReadSizesSupported));
  572. settings.CDDASupported = TRUE;
  573. settings.CDDAAccurate = FALSE;
  574. } else if (settings.CDDAAccurate) {
  575. ChkPrintEx(("StorageSeed: Drive is fully accurate\n"));
  576. settings.CDDASupported = TRUE;
  577. settings.ReadSizesSupported = -1;
  578. } else if (settings.CDDASupported) {
  579. ChkPrintEx(("StorageSeed: Drive lies about being accurate\n"));
  580. settings.CDDAAccurate = FALSE;
  581. settings.ReadSizesSupported = -1;
  582. } // values are now interpreted
  583. *Settings = settings;
  584. return;
  585. } // end of successful open of key
  586. DWORD
  587. StorageCoInstaller(
  588. IN DI_FUNCTION InstallFunction,
  589. IN HDEVINFO DeviceInfoSet,
  590. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  591. IN OUT PCOINSTALLER_CONTEXT_DATA Context
  592. )
  593. /*++
  594. Routine Description:
  595. This routine acts as a co-installer for storage devices. It is presently
  596. registered (via hivesys.inf) for CDROM, DiskDrive, and TapeDrive classes.
  597. The purpose of this co-installer is to save away the bus-supplied default
  598. DeviceDesc into the device's FriendlyName property. The reason for this
  599. is that the bus can retrieve a very specific description from the device
  600. (e.g., via SCSI inquiry data), yet the driver node we install will often
  601. be something very generic (e.g., "Disk drive").
  602. We want to keep the descriptive name, so that it can be displayed in the
  603. UI (DevMgr, etc.) to allow the user to distinguish between multiple storage
  604. devices of the same class.
  605. A secondary purpose for this co-installer is to seed the ability to play
  606. digital audio for a given device. The reason for this is that many cdroms
  607. that support digital audio do not report this ability, there are some that
  608. claim this ability but cannot actually do it reliably, and some that only
  609. work when reading N sectors at a time. This information is seeded in the
  610. registry, and copied to the enum key. If this information does not exist,
  611. no keys are created, and defaults are used.
  612. Arguments:
  613. InstallFunction - Specifies the device installer function code indicating
  614. the action being performed.
  615. DeviceInfoSet - Supplies a handle to the device information set being
  616. acted upon by this install action.
  617. DeviceInfoData - Optionally, supplies the address of a device information
  618. element being acted upon by this install action.
  619. Context - Supplies the installation context that is per-install
  620. request/per-coinstaller.
  621. Return Value:
  622. If this function successfully completed the requested action (or did
  623. nothing) and wishes for the installation to continue, the return
  624. value is NO_ERROR.
  625. If this function successfully completed the requested action (or did
  626. nothing) and would like to be called back once installation has
  627. completed, the return value is ERROR_DI_POSTPROCESSING_REQUIRED.
  628. If an error occurred while attempting to perform the requested action,
  629. a Win32 error code is returned. Installation will be aborted.
  630. --*/
  631. {
  632. PSTORAGE_COINSTALLER_CONTEXT InstallContext;
  633. PWSTR DeviceDescBuffer = NULL;
  634. DWORD DeviceDescBufferLen, Err;
  635. ULONG ulStatus, ulProblem;
  636. switch(InstallFunction) {
  637. case DIF_INSTALLDEVICE : {
  638. if(Context->PostProcessing) {
  639. //
  640. // We're 'on the way out' of an installation. The context
  641. // PrivateData had better contain the string we stored on
  642. // the way in.
  643. //
  644. InstallContext = Context->PrivateData;
  645. MYASSERT(InstallContext);
  646. //
  647. // We only want to store the FriendlyName property if the
  648. // installation succeeded. We only want to seed redbook values
  649. // if the install succeeded.
  650. //
  651. if(Context->InstallResult == NO_ERROR) {
  652. BOOLEAN OverrideFriendlyName = FALSE;
  653. if (IsEqualGUID(&(DeviceInfoData->ClassGuid),
  654. &GUID_DEVCLASS_TAPEDRIVE)) {
  655. //
  656. // This function checks if we need to use
  657. // the device description, given in INF file,
  658. // in UI such as Device Manager. Returns TRUE
  659. // if INF description is to used. FALSE, otherwise.
  660. //
  661. OverrideFriendlyName = OverrideFriendlyNameForTape(
  662. DeviceInfoSet,
  663. DeviceInfoData);
  664. } else if (IsEqualGUID(&(DeviceInfoData->ClassGuid),
  665. &GUID_DEVCLASS_CDROM)) {
  666. //
  667. // See if we need to install any of the filter drivers
  668. // to enable additional CD-ROM (CD-R, DVD-RAM, etc...)
  669. // features.
  670. //
  671. StorageInstallCdrom(DeviceInfoSet,
  672. DeviceInfoData,
  673. InstallContext,
  674. FALSE);
  675. }
  676. if ((OverrideFriendlyName == FALSE) &&
  677. (InstallContext->DeviceDescBuffer != NULL)) {
  678. //
  679. // If we need not use the INF device description
  680. // write the name, generated from SCSI Inquiry data,
  681. // onto FriendlyName
  682. //
  683. SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
  684. DeviceInfoData,
  685. SPDRP_FRIENDLYNAME,
  686. (PBYTE) InstallContext->DeviceDescBuffer,
  687. (lstrlen(InstallContext->DeviceDescBuffer) + 1) * sizeof(WCHAR));
  688. }
  689. }
  690. //
  691. // Now free our installation context.
  692. //
  693. if ((InstallContext->DeviceEnumKey) != INVALID_HANDLE_VALUE) {
  694. RegCloseKey(InstallContext->DeviceEnumKey);
  695. }
  696. if(InstallContext->DeviceDescBuffer) {
  697. MyFree(InstallContext->DeviceDescBuffer);
  698. }
  699. MyFree(InstallContext);
  700. //
  701. // Propagate the result of the previous installer.
  702. //
  703. return Context->InstallResult;
  704. } else {
  705. //
  706. // We're 'on the way in' for device installation.
  707. // Make sure that whoever called SetupDiCallClassInstaller
  708. // passed in a device information element. (Don't fail the
  709. // call if they didn't--that's the job of the class
  710. // installer/SetupDiInstallDevice.)
  711. //
  712. if(!DeviceInfoData) {
  713. return NO_ERROR;
  714. }
  715. //
  716. // Make sure this isn't a root-enumerated device. The root
  717. // enumerator clearly has nothing interesting to say about
  718. // the device's description beyond what the INF says.
  719. //
  720. if((CM_Get_DevNode_Status(&ulStatus, &ulProblem, DeviceInfoData->DevInst, 0) != CR_SUCCESS) ||
  721. (ulStatus & DN_ROOT_ENUMERATED)) {
  722. return NO_ERROR;
  723. }
  724. //
  725. // Allocate our context.
  726. //
  727. InstallContext = MyMalloc(sizeof(STORAGE_COINSTALLER_CONTEXT));
  728. if(InstallContext == NULL) {
  729. return NO_ERROR;
  730. }
  731. memset(InstallContext, 0, sizeof(STORAGE_COINSTALLER_CONTEXT));
  732. InstallContext->DeviceEnumKey = INVALID_HANDLE_VALUE;
  733. //
  734. // open the device's instance under the enum key
  735. //
  736. InstallContext->DeviceEnumKey = SetupDiCreateDevRegKey(
  737. DeviceInfoSet,
  738. DeviceInfoData,
  739. DICS_FLAG_GLOBAL,
  740. 0,
  741. DIREG_DEV,
  742. NULL,
  743. NULL);
  744. if (InstallContext->DeviceEnumKey == INVALID_HANDLE_VALUE) {
  745. ChkPrintEx(("StorageInstallCdrom: Failed to open device "
  746. "registry key\n"));
  747. }
  748. //
  749. // Search the device settings database to see if there are
  750. // any settings provided for this particular device.
  751. //
  752. if (InstallContext->DeviceEnumKey != INVALID_HANDLE_VALUE) {
  753. StorageCopyDeviceSettings(DeviceInfoSet,
  754. DeviceInfoData,
  755. InstallContext->DeviceEnumKey);
  756. }
  757. //
  758. // See if we need to install any of the filter drivers to enable
  759. // additional CD-ROM (CD-R, DVD-RAM, etc...) features.
  760. //
  761. if (IsEqualGUID(&(DeviceInfoData->ClassGuid),
  762. &GUID_DEVCLASS_CDROM)) {
  763. StorageInstallCdrom(DeviceInfoSet,
  764. DeviceInfoData,
  765. InstallContext,
  766. TRUE);
  767. }
  768. //
  769. // See if there is currently a 'FriendlyName' property.
  770. //
  771. if(SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  772. DeviceInfoData,
  773. SPDRP_FRIENDLYNAME,
  774. NULL,
  775. NULL,
  776. 0,
  777. NULL) ||
  778. (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
  779. //
  780. // Either we succeeded (which should never happen), or we
  781. // failed with a return value of buffer-too-small,
  782. // indicating that the property already exists. In this
  783. // case, there's nothing for us to do.
  784. //
  785. goto CoPreInstallDone;
  786. }
  787. //
  788. // Attempt to retrieve the DeviceDesc property.
  789. // start out with a buffer size that should always be big enough
  790. //
  791. DeviceDescBufferLen = LINE_LEN * sizeof(WCHAR);
  792. while(TRUE) {
  793. if(!(DeviceDescBuffer = MyMalloc(DeviceDescBufferLen))) {
  794. //
  795. // We failed, but what we're doing is not at all
  796. // critical. Thus, we'll go ahead and let the
  797. // installation proceed. If we're out of memory, it's
  798. // going to fail for a much more important reason
  799. // later anyway.
  800. //
  801. goto CoPreInstallDone;
  802. }
  803. if(SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  804. DeviceInfoData,
  805. SPDRP_DEVICEDESC,
  806. NULL,
  807. (PBYTE)DeviceDescBuffer,
  808. DeviceDescBufferLen,
  809. &DeviceDescBufferLen)) {
  810. break;
  811. }
  812. Err = GetLastError();
  813. //
  814. // Free our current buffer before examining the
  815. // cause of failure.
  816. //
  817. MyFree(DeviceDescBuffer);
  818. DeviceDescBuffer = NULL;
  819. if(Err != ERROR_INSUFFICIENT_BUFFER) {
  820. //
  821. // The failure was for some other reason than
  822. // buffer-too-small. This means we're not going to
  823. // be able to get the DeviceDesc (most likely because
  824. // the bus driver didn't supply us one. There's
  825. // nothing more we can do.
  826. //
  827. goto CoPreInstallDone;
  828. }
  829. }
  830. CoPreInstallDone:
  831. //
  832. // Save the device description buffer away.
  833. //
  834. InstallContext->DeviceDescBuffer = DeviceDescBuffer;
  835. //
  836. // Store the installer context in the context structure and
  837. // request a post-processing callback.
  838. //
  839. Context->PrivateData = InstallContext;
  840. return ERROR_DI_POSTPROCESSING_REQUIRED;
  841. }
  842. }
  843. default :
  844. //
  845. // We should always be 'on the way in', since we never request
  846. // postprocessing except for DIF_INSTALLDEVICE.
  847. //
  848. MYASSERT(!Context->PostProcessing);
  849. return NO_ERROR;
  850. }
  851. }
  852. DWORD
  853. VolumeClassInstaller(
  854. IN DI_FUNCTION InstallFunction,
  855. IN HDEVINFO DeviceInfoSet,
  856. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  857. )
  858. /*++
  859. Routine Description:
  860. This routine is the class installer function for storage volumes.
  861. Arguments:
  862. InstallFunction - Supplies the install function.
  863. DeviceInfoSet - Supplies the device info set.
  864. DeviceInfoData - Supplies the device info data.
  865. Return Value:
  866. If this function successfully completed the requested action, the return
  867. value is NO_ERROR.
  868. If the default behavior is to be performed for the requested action, the
  869. return value is ERROR_DI_DO_DEFAULT.
  870. If an error occurred while attempting to perform the requested action, a
  871. Win32 error code is returned.
  872. --*/
  873. {
  874. return ERROR_DI_DO_DEFAULT;
  875. }
  876. BOOLEAN
  877. OverrideFriendlyNameForTape(
  878. IN HDEVINFO DeviceInfoSet,
  879. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  880. )
  881. /*++
  882. Routine Description:
  883. This routine checks the device description, given in the INF, for
  884. the tape being installed. If the device description is a generic
  885. name (Tape drive), then we use the name generated from Inquiry
  886. data in UI such as Device Manager. If the INF provides a specific
  887. name, then we use that instead.
  888. Arguments:
  889. DeviceInfoSet - Supplies the device info set.
  890. DeviceInfoData - Supplies the device info data.
  891. Return Value:
  892. TRUE : If the device description given in the INF should be
  893. used as FriendlyName
  894. FALSE : If the name generated from Inquiry data should be
  895. used as FriendlyName instead of the name given in INF
  896. */
  897. {
  898. SP_DRVINFO_DETAIL_DATA drvDetData;
  899. SP_DRVINFO_DATA drvData;
  900. DWORD dwSize;
  901. TCHAR szSection[LINE_LEN];
  902. HINF hInf;
  903. INFCONTEXT infContext;
  904. BOOLEAN OverrideFriendlyName = FALSE;
  905. TCHAR szSectionName[LINE_LEN];
  906. ZeroMemory(&drvData, sizeof(SP_DRVINFO_DATA));
  907. drvData.cbSize = sizeof(SP_DRVINFO_DATA);
  908. if (!SetupDiGetSelectedDriver(DeviceInfoSet, DeviceInfoData, &drvData)) {
  909. return FALSE;
  910. }
  911. ZeroMemory(&drvDetData, sizeof(SP_DRVINFO_DETAIL_DATA));
  912. drvDetData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  913. if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
  914. DeviceInfoData,
  915. &drvData,
  916. &drvDetData,
  917. drvDetData.cbSize,
  918. &dwSize) &&
  919. GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  920. return FALSE;
  921. }
  922. hInf = SetupOpenInfFile(drvDetData.InfFileName,
  923. NULL,
  924. INF_STYLE_WIN4,
  925. NULL);
  926. if (hInf == INVALID_HANDLE_VALUE) {
  927. return FALSE;
  928. }
  929. //
  930. // Get the actual device install section name
  931. //
  932. ZeroMemory(szSectionName, sizeof(szSectionName));
  933. SetupDiGetActualSectionToInstall(hInf,
  934. drvDetData.SectionName,
  935. szSectionName,
  936. sizeof(szSectionName) / sizeof(TCHAR),
  937. NULL,
  938. NULL
  939. );
  940. if (SetupFindFirstLine(hInf, szSectionName,
  941. TEXT("UseInfDeviceDesc"),
  942. &infContext)) {
  943. DWORD UseDeviceDesc = 0;
  944. if ((SetupGetIntField(&infContext, 1, (PINT)&UseDeviceDesc)) &&
  945. (UseDeviceDesc)) {
  946. //
  947. // Delete friendly name if it exists.
  948. // Device Description will be used here on.
  949. //
  950. SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
  951. DeviceInfoData,
  952. SPDRP_FRIENDLYNAME,
  953. NULL,
  954. 0);
  955. OverrideFriendlyName = TRUE;
  956. }
  957. }
  958. if (OverrideFriendlyName) {
  959. ChkPrintEx(("Will override friendly name\n"));
  960. } else {
  961. ChkPrintEx(("Will NOT override friendly name\n"));
  962. }
  963. SetupCloseInfFile(hInf);
  964. return OverrideFriendlyName;
  965. }
  966. BOOLEAN
  967. CopyKey(
  968. HKEY SourceKey,
  969. HKEY DestinationKey
  970. )
  971. {
  972. DWORD index = 0;
  973. DWORD numberOfKeys;
  974. DWORD numberOfValues;
  975. DWORD keyNameLength;
  976. DWORD valueNameLength;
  977. DWORD valueLength;
  978. DWORD nameLength;
  979. PTCHAR name = NULL;
  980. PVOID data = NULL;
  981. LONG status = ERROR_SUCCESS;
  982. //
  983. // Determine the largest name and data length of the values in this key.
  984. //
  985. status = RegQueryInfoKey(SourceKey,
  986. NULL,
  987. NULL,
  988. NULL,
  989. &numberOfKeys,
  990. &keyNameLength,
  991. NULL,
  992. &numberOfValues,
  993. &valueNameLength,
  994. &valueLength,
  995. NULL,
  996. NULL);
  997. if(status != ERROR_SUCCESS) {
  998. ChkPrintEx(("Error %d getting info for key %#0x\n", status, SourceKey));
  999. return FALSE;
  1000. }
  1001. //
  1002. // Determine the longer of the two name lengths, then account for the
  1003. // short lengths returned by the registry code (it leaves out the
  1004. // terminating NUL).
  1005. //
  1006. nameLength = max(valueNameLength, keyNameLength);
  1007. nameLength += 1;
  1008. //
  1009. // Allocate name and data buffers
  1010. //
  1011. name = MyMalloc(nameLength * sizeof(TCHAR));
  1012. if(name == NULL) {
  1013. return FALSE;
  1014. }
  1015. //
  1016. // there may not be any data to buffer.
  1017. //
  1018. if(valueLength != 0) {
  1019. data = MyMalloc(valueLength);
  1020. if(data == NULL) {
  1021. MyFree(name);
  1022. return FALSE;
  1023. }
  1024. }
  1025. //
  1026. // Enumerate each value in the SourceKey and copy it to the DestinationKey.
  1027. //
  1028. for(index = 0;
  1029. (index < numberOfValues) && (status != ERROR_NO_MORE_ITEMS);
  1030. index++) {
  1031. DWORD valueDataLength;
  1032. DWORD type;
  1033. valueNameLength = nameLength;
  1034. valueDataLength = valueLength;
  1035. //
  1036. // Read the value into the pre-allocated buffers.
  1037. //
  1038. status = RegEnumValue(SourceKey,
  1039. index,
  1040. name,
  1041. &valueNameLength,
  1042. NULL,
  1043. &type,
  1044. data,
  1045. &valueDataLength);
  1046. if(status != ERROR_SUCCESS) {
  1047. ChkPrintEx(("Error %d reading value %x\n", status, index));
  1048. continue;
  1049. }
  1050. //
  1051. // Now set this value in the destination key.
  1052. // If this fails there's not much we can do but continue on to the
  1053. // next value.
  1054. //
  1055. status = RegSetValueEx(DestinationKey,
  1056. name,
  1057. 0,
  1058. type,
  1059. data,
  1060. valueDataLength);
  1061. }
  1062. //
  1063. // Free the data buffer.
  1064. //
  1065. MyFree(data);
  1066. data = NULL;
  1067. status = ERROR_SUCCESS;
  1068. //
  1069. // Now enumerate each key in the SourceKey, create the same key in the
  1070. // desination key, open a handle to each one and recurse.
  1071. //
  1072. for(index = 0;
  1073. (index < numberOfKeys) && (status != ERROR_NO_MORE_ITEMS);
  1074. index++) {
  1075. FILETIME lastWriteTime;
  1076. HKEY newSourceKey;
  1077. HKEY newDestinationKey;
  1078. keyNameLength = nameLength;
  1079. status = RegEnumKeyEx(SourceKey,
  1080. index,
  1081. name,
  1082. &keyNameLength,
  1083. NULL,
  1084. NULL,
  1085. NULL,
  1086. &lastWriteTime);
  1087. if(status != ERROR_SUCCESS) {
  1088. ChkPrintEx(("Error %d enumerating source key %x\n", status, index));
  1089. continue;
  1090. }
  1091. //
  1092. // Open the source subkey.
  1093. //
  1094. status = RegOpenKeyEx(SourceKey,
  1095. name,
  1096. 0L,
  1097. KEY_READ,
  1098. &newSourceKey);
  1099. if(status != ERROR_SUCCESS) {
  1100. ChkPrintEx(("Error %d opening source key %x\n", status, index));
  1101. continue;
  1102. }
  1103. //
  1104. // Create the destination subkey.
  1105. //
  1106. status = RegCreateKeyEx(DestinationKey,
  1107. name,
  1108. 0L,
  1109. NULL,
  1110. REG_OPTION_NON_VOLATILE,
  1111. KEY_WRITE,
  1112. NULL,
  1113. &newDestinationKey,
  1114. NULL);
  1115. if(status != ERROR_SUCCESS) {
  1116. ChkPrintEx(("Error %d creating dest key %x\n", status, index));
  1117. RegCloseKey(newSourceKey);
  1118. continue;
  1119. }
  1120. //
  1121. // Recursively copy this key.
  1122. //
  1123. CopyKey(newSourceKey, newDestinationKey);
  1124. RegCloseKey(newSourceKey);
  1125. RegCloseKey(newDestinationKey);
  1126. }
  1127. //
  1128. // Now free the name buffer.
  1129. //
  1130. MyFree(name);
  1131. return TRUE;
  1132. }
  1133. BOOLEAN
  1134. StorageCopyDeviceSettings(
  1135. IN HDEVINFO DeviceInfo,
  1136. IN PSP_DEVINFO_DATA DeviceInfoData,
  1137. IN HKEY DeviceEnumKey
  1138. )
  1139. {
  1140. PTCHAR hardwareIdList = NULL;
  1141. PTCHAR hardwareId = NULL;
  1142. DWORD requiredSize = 0;
  1143. HKEY settingsDatabaseKey = INVALID_HANDLE_VALUE;
  1144. BOOLEAN settingsCopied = FALSE;
  1145. DWORD status;
  1146. ASSERT(DeviceInfo != NULL);
  1147. ASSERT(DeviceInfoData != NULL);
  1148. //
  1149. // Open the device settings key.
  1150. //
  1151. status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1152. STORAGE_DEVICE_SETTINGS_DATABASE,
  1153. 0L,
  1154. KEY_READ,
  1155. &settingsDatabaseKey);
  1156. if(status != ERROR_SUCCESS) {
  1157. ChkPrintEx(("StorageCopyDeviceSettings: Error %d opening "
  1158. "settings database\n",
  1159. status));
  1160. return FALSE;
  1161. }
  1162. //
  1163. // get the hardware id's
  1164. //
  1165. if(SetupDiGetDeviceRegistryProperty(DeviceInfo,
  1166. DeviceInfoData,
  1167. SPDRP_HARDWAREID,
  1168. NULL,
  1169. NULL,
  1170. 0,
  1171. &requiredSize) ||
  1172. (requiredSize == 0)) {
  1173. //
  1174. // That's odd.
  1175. //
  1176. ChkPrintEx(("StorageCopyDeviceSettings: no hardware ids available?\n"));
  1177. goto cleanup;
  1178. }
  1179. //
  1180. // requiredSize is bytes, not characters
  1181. //
  1182. hardwareIdList = MyMalloc(requiredSize);
  1183. if (hardwareIdList == NULL) {
  1184. ChkPrintEx(("StorageCopyDeviceSettings: Couldn't allocate %d bytes "
  1185. "for HWIDs\n", requiredSize));
  1186. goto cleanup;
  1187. }
  1188. if(!SetupDiGetDeviceRegistryProperty(DeviceInfo,
  1189. DeviceInfoData,
  1190. SPDRP_HARDWAREID,
  1191. NULL,
  1192. (PBYTE)hardwareIdList,
  1193. requiredSize,
  1194. NULL)) {
  1195. ChkPrintEx(("StorageCopyDeviceSettings: failed to get "
  1196. "device's hardware ids %x\n",
  1197. GetLastError()));
  1198. goto cleanup;
  1199. }
  1200. //
  1201. // Look in the device settings database for a matching hardware ID. When
  1202. // we find a match copy the contents of that key under the device's
  1203. // devnode key.
  1204. //
  1205. // The hardware IDs we get back from SetupDi are sorted from most exact
  1206. // to least exact so we're guaranteed to find the closest match first.
  1207. //
  1208. hardwareId = hardwareIdList;
  1209. while(hardwareId[0] != TCHAR_NULL) {
  1210. HKEY deviceSettingsKey;
  1211. LONG openStatus;
  1212. //
  1213. // Replace slashes with #'s so that it's compatible as a registry
  1214. // key name.
  1215. //
  1216. ReplaceSlashWithHash(hardwareId);
  1217. openStatus = RegOpenKeyEx(settingsDatabaseKey,
  1218. hardwareId,
  1219. 0,
  1220. KEY_READ,
  1221. &deviceSettingsKey);
  1222. if (openStatus == ERROR_SUCCESS) {
  1223. //StorageReadSettings(specialTargetHandle, &settings);
  1224. CopyKey(deviceSettingsKey, DeviceEnumKey);
  1225. settingsCopied = TRUE;
  1226. RegCloseKey(deviceSettingsKey);
  1227. break;
  1228. }
  1229. // get to next null, for statement will advance past it
  1230. while (*hardwareId) {
  1231. hardwareId += 1;
  1232. }
  1233. //
  1234. // Skip the nul and go to the next tchar.
  1235. //
  1236. hardwareId += 1;
  1237. RegCloseKey(deviceSettingsKey);
  1238. } // end of loop for query'ing each id
  1239. cleanup:
  1240. ChkPrintEx(("StorageCopyDeviceSettings: Cleaning up...\n"));
  1241. if (settingsDatabaseKey != INVALID_HANDLE_VALUE) {
  1242. RegCloseKey(settingsDatabaseKey);
  1243. }
  1244. if (hardwareIdList != NULL) {
  1245. MyFree(hardwareIdList);
  1246. }
  1247. return settingsCopied;
  1248. }
  1249. VOID
  1250. StorageInstallCdrom(
  1251. IN HDEVINFO DeviceInfo,
  1252. IN PSP_DEVINFO_DATA DeviceInfoData,
  1253. IN PSTORAGE_COINSTALLER_CONTEXT InstallContext,
  1254. IN BOOLEAN PreInstall
  1255. )
  1256. {
  1257. CDVD_CAPABILITIES_PAGE buffer;
  1258. PCDVD_CAPABILITIES_PAGE page = NULL;
  1259. BOOLEAN installRedbook = FALSE;
  1260. BOOLEAN installImapi = FALSE;
  1261. BOOLEAN needRestart = FALSE;
  1262. //
  1263. // If this is post-installation then get the device capabilities page and
  1264. // provide it to the update routines.
  1265. //
  1266. if(PreInstall == FALSE) {
  1267. if(StorageGetCDVDCapabilities(DeviceInfo, DeviceInfoData, &buffer)) {
  1268. page = &buffer;
  1269. }
  1270. }
  1271. //
  1272. // Check in the registry (or query the device) and determine if we should
  1273. // enable the redbook (digital audio playback) driver on this device.
  1274. //
  1275. // If redbook was already installed the first time through then there's no
  1276. // need to do this step
  1277. //
  1278. if((PreInstall == TRUE) ||
  1279. ((InstallContext->CdRom.RedbookInstalled == FALSE) && (page != NULL))) {
  1280. if ((InstallContext->DeviceEnumKey) != INVALID_HANDLE_VALUE) {
  1281. installRedbook = StorageUpdateRedbookSettings(
  1282. DeviceInfo,
  1283. DeviceInfoData,
  1284. InstallContext->DeviceEnumKey,
  1285. page);
  1286. }
  1287. }
  1288. //
  1289. // Check in the registry (or query the device) and determine if we should
  1290. // enable the IMAPI driver on this device.
  1291. //
  1292. // If imapi was already installed the first time through then there's no
  1293. // need to do this step
  1294. //
  1295. if((PreInstall == TRUE) ||
  1296. ((InstallContext->CdRom.ImapiInstalled == FALSE) && (page != NULL))) {
  1297. if ((InstallContext->DeviceEnumKey) != INVALID_HANDLE_VALUE) {
  1298. installImapi = StorageUpdateImapiSettings(DeviceInfo,
  1299. DeviceInfoData,
  1300. InstallContext->DeviceEnumKey,
  1301. page);
  1302. }
  1303. }
  1304. //
  1305. // If this is a pre-install pass then we can just add the services. If it's
  1306. // not then first check to see that we don't do anything here that we
  1307. // already did in the pre-install pass.
  1308. //
  1309. if(PreInstall) {
  1310. //
  1311. // Save away what we've done during the pre-install pass.
  1312. //
  1313. InstallContext->CdRom.RedbookInstalled = installRedbook;
  1314. InstallContext->CdRom.ImapiInstalled = installImapi;
  1315. }
  1316. //
  1317. // If we're supposed to enable IMAPI then do so by enabling the IMAPI
  1318. // service and including it in the list of lower filters for this device.
  1319. //
  1320. if(installRedbook) {
  1321. ChkPrintEx(("StorageInstallCdrom: Installing Upperfilter: REDBOOK\n"));
  1322. StorageInstallFilter(DeviceInfo,
  1323. DeviceInfoData,
  1324. REDBOOK_SERVICE_NAME,
  1325. SPDRP_UPPERFILTERS);
  1326. needRestart = TRUE;
  1327. }
  1328. if(installImapi) {
  1329. ChkPrintEx(("StorageInstallCdrom: Installing Lowerfilter: IMAPI\n"));
  1330. StorageInstallFilter(DeviceInfo,
  1331. DeviceInfoData,
  1332. IMAPI_SERVICE_NAME,
  1333. SPDRP_LOWERFILTERS);
  1334. needRestart = TRUE;
  1335. }
  1336. if((PreInstall == FALSE) && (needRestart == TRUE)) {
  1337. SP_PROPCHANGE_PARAMS propChange;
  1338. //
  1339. // The device is all set but we to indicate that a property change
  1340. // has occurred. Set the propchange_pending flag which should cause
  1341. // a DIF_PROPERTYCHANGE command to get sent through, which we'll use
  1342. // to restart the device.
  1343. //
  1344. ChkPrintEx(("StorageInstallCdrom: Calling class installer with DIF_PROPERTYCHANGE\n"));
  1345. propChange.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  1346. propChange.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
  1347. propChange.StateChange = DICS_PROPCHANGE;
  1348. propChange.Scope = DICS_FLAG_GLOBAL;
  1349. propChange.HwProfile = 0;
  1350. SetupDiSetClassInstallParams(DeviceInfo,
  1351. DeviceInfoData,
  1352. &propChange.ClassInstallHeader,
  1353. sizeof(SP_PROPCHANGE_PARAMS));
  1354. SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
  1355. DeviceInfo,
  1356. DeviceInfoData);
  1357. }
  1358. return;
  1359. }
  1360. BOOLEAN
  1361. StorageUpdateRedbookSettings(
  1362. IN HDEVINFO DeviceInfo,
  1363. IN PSP_DEVINFO_DATA DeviceInfoData,
  1364. IN HKEY DeviceEnumKey,
  1365. IN PCDVD_CAPABILITIES_PAGE CapabilitiesPage OPTIONAL
  1366. )
  1367. {
  1368. STORAGE_REDBOOK_SETTINGS settings;
  1369. HKEY redbookKey;
  1370. DWORD setFromDevice = FALSE;
  1371. DWORD disposition;
  1372. DWORD status;
  1373. settings.CDDASupported = FALSE;
  1374. settings.CDDAAccurate = FALSE;
  1375. settings.ReadSizesSupported = 0;
  1376. //
  1377. // Open the digital audio subkey of the device's enum key. If the device
  1378. // hasn't been started yet then we won't create the key. Otherwise we
  1379. // will create it and populate it.
  1380. //
  1381. if(ARGUMENT_PRESENT(CapabilitiesPage)) {
  1382. status = RegCreateKeyEx(DeviceEnumKey,
  1383. REDBOOK_SETTINGS_KEY,
  1384. 0L,
  1385. NULL,
  1386. REG_OPTION_NON_VOLATILE,
  1387. KEY_READ | KEY_WRITE,
  1388. NULL,
  1389. &redbookKey,
  1390. &disposition
  1391. );
  1392. } else {
  1393. status = RegOpenKeyEx(DeviceEnumKey,
  1394. REDBOOK_SETTINGS_KEY,
  1395. 0L,
  1396. KEY_READ | KEY_WRITE,
  1397. &redbookKey);
  1398. disposition = REG_OPENED_EXISTING_KEY;
  1399. }
  1400. if(status != ERROR_SUCCESS) {
  1401. ChkPrintEx(("StorageUpdateRedbookSettings: couldn't open redbook key "
  1402. "- %d\n", status));
  1403. return FALSE;
  1404. }
  1405. if(disposition == REG_OPENED_EXISTING_KEY) {
  1406. //
  1407. // Read the redbook settings out of the registry (if there are any) and
  1408. // see if they make any sense.
  1409. //
  1410. StorageReadRedbookSettings(redbookKey, &settings);
  1411. } else {
  1412. //
  1413. // Since the DigitalAudio key didn't exist nothing could be set. Check
  1414. // with the device to see what it supports.
  1415. //
  1416. MYASSERT(CapabilitiesPage != NULL);
  1417. settings.CDDASupported = CapabilitiesPage->CDDA;
  1418. settings.CDDAAccurate = CapabilitiesPage->CDDAAccurate;
  1419. //
  1420. // If the device isn't accurate then we can't be quite sure what the valid
  1421. // read sizes are (unless they were listed in the registry, but in that case
  1422. // we'd never have been here). Use zero, which is a special value for
  1423. // ReadSizesSupported which means "i don't know".
  1424. //
  1425. if((settings.CDDASupported == TRUE) &&
  1426. (settings.CDDAAccurate == TRUE)) {
  1427. settings.ReadSizesSupported = -1;
  1428. }
  1429. setFromDevice = TRUE;
  1430. }
  1431. //
  1432. // Write the updated (or derived) settings to the registry.
  1433. //
  1434. if (settings.CDDAAccurate) {
  1435. ChkPrintEx(("StorageUpdateRedbookSettings: "
  1436. "Cdrom fully supports CDDA.\n"));
  1437. } else if (settings.ReadSizesSupported) {
  1438. ChkPrintEx(("StorageUpdateRedbookSettings: "
  1439. "Cdrom only supports some sizes CDDA read.\n"));
  1440. ChkPrintEx(("StorageUpdateRedbookSettings: "
  1441. "These are in the bitmask: %x.\n",
  1442. settings.ReadSizesSupported));
  1443. } else if (settings.CDDASupported) {
  1444. ChkPrintEx(("StorageUpdateRedbookSettings: "
  1445. "Cdrom only supports some sizes CDDA read.\n"));
  1446. ChkPrintEx(("StorageUpdateRedbookSettings: "
  1447. "There is no data on which sizes (if any) "
  1448. "are accurate\n"));
  1449. } else {
  1450. ChkPrintEx(("StorageUpdateRedbookSettings: "
  1451. "Cdrom does not support CDDA at all.\n"));
  1452. }
  1453. RegSetValueEx(redbookKey,
  1454. L"ReadSizesSupported",
  1455. 0,
  1456. REG_DWORD,
  1457. (BYTE*)&settings.ReadSizesSupported,
  1458. sizeof(DWORD)
  1459. );
  1460. RegSetValueEx(redbookKey,
  1461. L"CDDASupported",
  1462. 0,
  1463. REG_DWORD,
  1464. (BYTE*)&settings.CDDASupported,
  1465. sizeof(DWORD)
  1466. );
  1467. RegSetValueEx(redbookKey,
  1468. L"CDDAAccurate",
  1469. 0,
  1470. REG_DWORD,
  1471. (BYTE*)&settings.CDDAAccurate,
  1472. sizeof(DWORD)
  1473. );
  1474. RegSetValueEx(redbookKey,
  1475. L"SettingsFromDevice",
  1476. 0,
  1477. REG_DWORD,
  1478. (LPBYTE) &(setFromDevice),
  1479. sizeof(DWORD)
  1480. );
  1481. RegCloseKey(redbookKey);
  1482. //
  1483. // if CDDA is supported, and one of:
  1484. // CDDA is accurate
  1485. // We have a mask of accurate settings
  1486. // We want to force install of redbook
  1487. // is true, then return TRUE.
  1488. // else, return FALSE.
  1489. //
  1490. if((settings.CDDASupported) &&
  1491. ((settings.CDDAAccurate) ||
  1492. (settings.ReadSizesSupported != 0) ||
  1493. (StorageForceRedbookOnInaccurateDrives))) {
  1494. return TRUE;
  1495. } else {
  1496. return FALSE;
  1497. }
  1498. }
  1499. BOOLEAN
  1500. StorageUpdateImapiSettings(
  1501. IN HDEVINFO DeviceInfo,
  1502. IN PSP_DEVINFO_DATA DeviceInfoData,
  1503. IN HKEY DeviceEnumKey,
  1504. IN PCDVD_CAPABILITIES_PAGE CapabilitiesPage OPTIONAL
  1505. )
  1506. {
  1507. HKEY imapiKey;
  1508. DWORD disposition;
  1509. DWORD status;
  1510. //
  1511. // must be a DWORD so we can read into it from the registry.
  1512. //
  1513. DWORD enableImapi = FALSE;
  1514. //
  1515. // Open the imapi subkey of the device's enum key. If the device has been
  1516. // started then we'll create the key if it didn't already exist.
  1517. //
  1518. if(ARGUMENT_PRESENT(CapabilitiesPage)) {
  1519. status = RegCreateKeyEx(DeviceEnumKey,
  1520. IMAPI_SETTINGS_KEY,
  1521. 0L,
  1522. NULL,
  1523. REG_OPTION_NON_VOLATILE,
  1524. KEY_READ | KEY_WRITE,
  1525. NULL,
  1526. &imapiKey,
  1527. &disposition
  1528. );
  1529. } else {
  1530. status = RegOpenKeyEx(DeviceEnumKey,
  1531. IMAPI_SETTINGS_KEY,
  1532. 0L,
  1533. KEY_READ | KEY_WRITE,
  1534. &imapiKey
  1535. );
  1536. disposition = REG_OPENED_EXISTING_KEY;
  1537. }
  1538. if(status != ERROR_SUCCESS) {
  1539. ChkPrintEx(("StorageUpdateImapiSettings: couldn't open imapi key "
  1540. "- %d\n", status));
  1541. return FALSE;
  1542. }
  1543. if(disposition == REG_OPENED_EXISTING_KEY) {
  1544. DWORD type = REG_DWORD;
  1545. DWORD dataSize = sizeof(DWORD);
  1546. //
  1547. // Check to see if the EnableImapi value is set in this key. If it is
  1548. // then we'll be wanting to enable the filter driver.
  1549. //
  1550. status = RegQueryValueEx(imapiKey,
  1551. IMAPI_ENABLE_VALUE,
  1552. NULL,
  1553. &type,
  1554. (LPBYTE) &enableImapi,
  1555. &dataSize);
  1556. if (status == ERROR_SUCCESS) {
  1557. if(type != REG_DWORD) {
  1558. ChkPrintEx(("StorageUpdateImapiSettings: EnableImapi value is of "
  1559. "type %d\n", type));
  1560. enableImapi = FALSE;
  1561. }
  1562. RegCloseKey(imapiKey);
  1563. return (BOOLEAN) enableImapi ? TRUE : FALSE;
  1564. }
  1565. //
  1566. // else the key wasn't accessible. fall through to query the drive
  1567. //
  1568. }
  1569. if(ARGUMENT_PRESENT(CapabilitiesPage)) {
  1570. //
  1571. // query the drive to see if it supports mastering...
  1572. //
  1573. if((CapabilitiesPage->CDRWrite) || (CapabilitiesPage->CDEWrite)) {
  1574. enableImapi = TRUE;
  1575. }
  1576. }
  1577. if (enableImapi && DISABLE_IMAPI) {
  1578. ChkPrintEx(("StorageUpdateImapiSettings: Imapi would have "
  1579. "been enabled"));
  1580. enableImapi = FALSE;
  1581. }
  1582. if (enableImapi) {
  1583. //
  1584. // must add registry key listed above that suggests that
  1585. // imapi must be enabled by default.
  1586. //
  1587. status = RegSetValueEx(imapiKey,
  1588. IMAPI_ENABLE_VALUE,
  1589. 0,
  1590. REG_DWORD,
  1591. (BYTE*)&enableImapi,
  1592. sizeof(DWORD)
  1593. );
  1594. //
  1595. // if this failed, then the device driver won't attach itself
  1596. // to the stack. in this case, we don't want to enable IMAPI
  1597. // after all...
  1598. //
  1599. if (status != ERROR_SUCCESS) {
  1600. enableImapi = FALSE;
  1601. }
  1602. }
  1603. RegCloseKey(imapiKey);
  1604. return (BOOLEAN) enableImapi ? TRUE : FALSE;
  1605. }
  1606. DWORD
  1607. StorageInstallFilter(
  1608. IN HDEVINFO DeviceInfo,
  1609. IN PSP_DEVINFO_DATA DeviceInfoData,
  1610. IN LPTSTR FilterName,
  1611. IN DWORD FilterType
  1612. )
  1613. {
  1614. DWORD status;
  1615. DWORD oldStartType;
  1616. //
  1617. // Check with the service controller and make sure that the IMAPI service
  1618. // is set to start at system time.
  1619. //
  1620. status = SetServiceStart(FilterName, SERVICE_SYSTEM_START, &oldStartType);
  1621. if(status != ERROR_SUCCESS) {
  1622. return status;
  1623. }
  1624. //
  1625. // Add the IMAPI filter to the list of lower device filters.
  1626. //
  1627. status = AddFilterDriver(DeviceInfo,
  1628. DeviceInfoData,
  1629. FilterName,
  1630. FilterType
  1631. );
  1632. if(status != ERROR_SUCCESS) {
  1633. //
  1634. // if it failed, and the service was previously disabled,
  1635. // re-disable the service.
  1636. //
  1637. if(oldStartType == SERVICE_DISABLED) {
  1638. SetServiceStart(FilterName, SERVICE_DISABLED, &oldStartType);
  1639. }
  1640. }
  1641. return status;
  1642. }
  1643. DWORD
  1644. SetServiceStart(
  1645. IN LPCTSTR ServiceName,
  1646. IN DWORD StartType,
  1647. OUT DWORD *OldStartType
  1648. )
  1649. {
  1650. SC_HANDLE serviceManager;
  1651. SC_HANDLE service;
  1652. DWORD status;
  1653. serviceManager = OpenSCManager(NULL, NULL, GENERIC_READ | GENERIC_WRITE);
  1654. if(serviceManager == NULL) {
  1655. return GetLastError();
  1656. }
  1657. service = OpenService(serviceManager,
  1658. ServiceName,
  1659. SERVICE_CHANGE_CONFIG | SERVICE_QUERY_CONFIG);
  1660. if(service == NULL) {
  1661. status = GetLastError();
  1662. CloseServiceHandle(serviceManager);
  1663. return status;
  1664. }
  1665. {
  1666. QUERY_SERVICE_CONFIG configBuffer;
  1667. LPQUERY_SERVICE_CONFIG config = &(configBuffer);
  1668. DWORD configSize;
  1669. BOOLEAN wasStarted;
  1670. //
  1671. // Retrieve the configuration so we can get the current service
  1672. // start value. We unfortuantely need to allocate memory for the
  1673. // entire service configuration - the fine QueryServiceConfig API
  1674. // doesn't give back partial data.
  1675. //
  1676. memset(config, 0, sizeof(QUERY_SERVICE_CONFIG));
  1677. configSize = sizeof(QUERY_SERVICE_CONFIG);
  1678. //
  1679. // Determine the number of bytes needed for the configuration.
  1680. //
  1681. QueryServiceConfig(service, config, 0, &configSize);
  1682. status = GetLastError();
  1683. if(status != ERROR_INSUFFICIENT_BUFFER) {
  1684. CloseServiceHandle(service);
  1685. CloseServiceHandle(serviceManager);
  1686. return status;
  1687. }
  1688. //
  1689. // Allocate the appropriately sized config buffer.
  1690. //
  1691. config = MyMalloc(configSize);
  1692. if(config == NULL) {
  1693. CloseServiceHandle(service);
  1694. CloseServiceHandle(serviceManager);
  1695. return ERROR_NOT_ENOUGH_MEMORY;
  1696. }
  1697. if(!QueryServiceConfig(service, config, configSize, &configSize)) {
  1698. status = GetLastError();
  1699. CloseServiceHandle(service);
  1700. CloseServiceHandle(serviceManager);
  1701. MyFree(config);
  1702. return status;
  1703. }
  1704. //
  1705. // Record what the old start type was so that the caller can disable
  1706. // the service again if filter-installation fails.
  1707. //
  1708. *OldStartType = config->dwStartType;
  1709. //
  1710. // If the start type doesn't need to be changed then bail out now.
  1711. //
  1712. if(config->dwStartType == StartType) {
  1713. CloseServiceHandle(service);
  1714. CloseServiceHandle(serviceManager);
  1715. MyFree(config);
  1716. return ERROR_SUCCESS;
  1717. }
  1718. //
  1719. // Now write the configuration back to the service.
  1720. //
  1721. if(ChangeServiceConfig(service,
  1722. SERVICE_NO_CHANGE,
  1723. StartType,
  1724. SERVICE_NO_CHANGE,
  1725. NULL,
  1726. NULL,
  1727. NULL,
  1728. NULL,
  1729. NULL,
  1730. NULL,
  1731. NULL) == FALSE) {
  1732. status = GetLastError();
  1733. } else {
  1734. status = ERROR_SUCCESS;
  1735. }
  1736. CloseServiceHandle(service);
  1737. CloseServiceHandle(serviceManager);
  1738. MyFree(config);
  1739. }
  1740. return status;
  1741. }
  1742. DWORD
  1743. AddFilterDriver(
  1744. IN HDEVINFO DeviceInfo,
  1745. IN PSP_DEVINFO_DATA DeviceInfoData,
  1746. IN LPTSTR ServiceName,
  1747. IN DWORD FilterType
  1748. )
  1749. {
  1750. DWORD serviceNameLength = (_tcslen(ServiceName) + 2) * sizeof(TCHAR);
  1751. LPTSTR filterList = NULL;
  1752. DWORD filterListSize = 0;
  1753. DWORD type;
  1754. DWORD status;
  1755. ASSERT((FilterType == SPDRP_LOWERFILTERS) ||
  1756. (FilterType == SPDRP_UPPERFILTERS));
  1757. //
  1758. // Query to find out the property size. If it comes back zero then
  1759. // we'll just try to write the property in there.
  1760. //
  1761. SetupDiGetDeviceRegistryProperty(DeviceInfo,
  1762. DeviceInfoData,
  1763. FilterType,
  1764. &type,
  1765. NULL,
  1766. 0L,
  1767. &filterListSize);
  1768. status = GetLastError();
  1769. if((status != ERROR_INVALID_DATA) &&
  1770. (status != ERROR_INSUFFICIENT_BUFFER)) {
  1771. //
  1772. // If this succeeded with no buffer provided then there's something
  1773. // very odd going on.
  1774. //
  1775. ChkPrintEx(("Unable to get filter list: %x\n", status));
  1776. ASSERT(status != ERROR_SUCCESS);
  1777. return status;
  1778. }
  1779. //
  1780. // This error code appears to be returned if the property isn't set in the
  1781. // devnode. In that event make sure propertySize is cleared.
  1782. //
  1783. if(status == ERROR_INVALID_DATA) {
  1784. filterListSize = 0;
  1785. } else if(type != REG_MULTI_SZ) {
  1786. return ERROR_INVALID_DATA;
  1787. }
  1788. //
  1789. // If the property size is zero then there's nothing to query. Likewise,
  1790. // if it's equal to the size of two nul characters.
  1791. //
  1792. if(filterListSize >= (sizeof(TCHAR_NULL) * 2)) {
  1793. DWORD tmp;
  1794. LPTSTR listEnd;
  1795. //
  1796. // increase the filter list buffer size so that it can hold our
  1797. // addition. Make sure to take into account the extra nul character
  1798. // already in the existing list.
  1799. //
  1800. filterListSize += serviceNameLength - sizeof(TCHAR);
  1801. filterList = MyMalloc(filterListSize);
  1802. if(filterList == NULL) {
  1803. return ERROR_NOT_ENOUGH_MEMORY;
  1804. }
  1805. memset(filterList, 0, filterListSize);
  1806. //
  1807. // Query the registry information again.
  1808. //
  1809. if(!SetupDiGetDeviceRegistryProperty(DeviceInfo,
  1810. DeviceInfoData,
  1811. FilterType,
  1812. &type,
  1813. (PBYTE) filterList,
  1814. filterListSize,
  1815. &tmp)) {
  1816. status = GetLastError();
  1817. MyFree(filterList);
  1818. return status;
  1819. }
  1820. if(type != REG_MULTI_SZ) {
  1821. MyFree(filterList);
  1822. return ERROR_INVALID_DATA;
  1823. }
  1824. //
  1825. // Compute the end of the filter list and copy the imapi filters
  1826. // there.
  1827. //
  1828. listEnd = filterList;
  1829. listEnd += tmp / sizeof(TCHAR);
  1830. listEnd -= 1;
  1831. memset(listEnd, 0, serviceNameLength);
  1832. memcpy(listEnd, ServiceName, serviceNameLength - sizeof(TCHAR_NULL));
  1833. } else {
  1834. filterList = MyMalloc(serviceNameLength);
  1835. if(filterList == NULL) {
  1836. return ERROR_NOT_ENOUGH_MEMORY;
  1837. }
  1838. memset(filterList, 0, serviceNameLength);
  1839. memcpy(filterList, ServiceName, serviceNameLength - sizeof(TCHAR_NULL));
  1840. filterListSize = serviceNameLength;
  1841. }
  1842. if(!SetupDiSetDeviceRegistryProperty(DeviceInfo,
  1843. DeviceInfoData,
  1844. FilterType,
  1845. (PBYTE) filterList,
  1846. filterListSize)) {
  1847. status = GetLastError();
  1848. } else {
  1849. status = ERROR_SUCCESS;
  1850. }
  1851. MyFree(filterList);
  1852. return status;
  1853. }
  1854. /*++
  1855. Routine Description:
  1856. NOTE: we default to RETRY==TRUE except for known error classes
  1857. This is based upon classpnp's InterpretSenseInfo().
  1858. Arguments:
  1859. Return Value:
  1860. --*/
  1861. VOID
  1862. StorageInterpretSenseInfo(
  1863. IN PSENSE_DATA SenseData,
  1864. IN UCHAR SenseDataSize,
  1865. OUT PDWORD ErrorValue, // from WinError.h
  1866. OUT PBOOLEAN SuggestRetry OPTIONAL,
  1867. OUT PDWORD SuggestRetryDelay OPTIONAL // in 1/10 second intervals
  1868. )
  1869. {
  1870. DWORD error;
  1871. DWORD retryDelay;
  1872. BOOLEAN retry;
  1873. UCHAR senseKey;
  1874. UCHAR asc;
  1875. UCHAR ascq;
  1876. if (SenseDataSize == 0) {
  1877. retry = FALSE;
  1878. retryDelay = 0;
  1879. error = ERROR_IO_DEVICE;
  1880. goto SetAndExit;
  1881. }
  1882. //
  1883. // default to suggesting a retry in 1/10 of a second,
  1884. // with a status of ERROR_IO_DEVICE.
  1885. //
  1886. retry = TRUE;
  1887. retryDelay = 1;
  1888. error = ERROR_IO_DEVICE;
  1889. //
  1890. // if we can't even see the sense key, just return.
  1891. // can't use bitfields in these macros, so use next field
  1892. // instead of RTL_SIZEOF_THROUGH_FIELD
  1893. //
  1894. if (SenseDataSize < FIELD_OFFSET(SENSE_DATA, Information)) {
  1895. goto SetAndExit;
  1896. }
  1897. senseKey = SenseData->SenseKey;
  1898. //
  1899. // if the device succeeded the request, return success.
  1900. //
  1901. if (senseKey == 0) {
  1902. retry = FALSE;
  1903. retryDelay = 0;
  1904. error = ERROR_SUCCESS;
  1905. goto SetAndExit;
  1906. }
  1907. { // set the size to what's actually useful.
  1908. UCHAR validLength;
  1909. // figure out what we could have gotten with a large sense buffer
  1910. if (SenseDataSize <
  1911. RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength)) {
  1912. validLength = SenseDataSize;
  1913. } else {
  1914. validLength =
  1915. RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength);
  1916. validLength += SenseData->AdditionalSenseLength;
  1917. }
  1918. // use the smaller of the two values.
  1919. SenseDataSize = min(SenseDataSize, validLength);
  1920. }
  1921. if (SenseDataSize <
  1922. RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCode)) {
  1923. asc = SCSI_ADSENSE_NO_SENSE;
  1924. } else {
  1925. asc = SenseData->AdditionalSenseCode;
  1926. }
  1927. if (SenseDataSize <
  1928. RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCodeQualifier)) {
  1929. ascq = SCSI_SENSEQ_CAUSE_NOT_REPORTABLE; // 0x00
  1930. } else {
  1931. ascq = SenseData->AdditionalSenseCodeQualifier;
  1932. }
  1933. //
  1934. // interpret :P
  1935. //
  1936. switch (senseKey & 0xf) {
  1937. case SCSI_SENSE_RECOVERED_ERROR: { // 0x01
  1938. if (SenseData->IncorrectLength) {
  1939. error = ERROR_INVALID_BLOCK_LENGTH;
  1940. } else {
  1941. error = ERROR_SUCCESS;
  1942. }
  1943. retry = FALSE;
  1944. break;
  1945. } // end SCSI_SENSE_RECOVERED_ERROR
  1946. case SCSI_SENSE_NOT_READY: { // 0x02
  1947. error = ERROR_NOT_READY;
  1948. switch (asc) {
  1949. case SCSI_ADSENSE_LUN_NOT_READY: {
  1950. switch (ascq) {
  1951. case SCSI_SENSEQ_BECOMING_READY:
  1952. case SCSI_SENSEQ_OPERATION_IN_PROGRESS: {
  1953. retryDelay = PASS_THROUGH_NOT_READY_RETRY_INTERVAL;
  1954. break;
  1955. }
  1956. case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE:
  1957. case SCSI_SENSEQ_FORMAT_IN_PROGRESS:
  1958. case SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS: {
  1959. retry = FALSE;
  1960. break;
  1961. }
  1962. case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED: {
  1963. retry = FALSE;
  1964. break;
  1965. }
  1966. } // end switch (senseBuffer->AdditionalSenseCodeQualifier)
  1967. break;
  1968. }
  1969. case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE: {
  1970. error = ERROR_NOT_READY;
  1971. retry = FALSE;
  1972. break;
  1973. }
  1974. } // end switch (senseBuffer->AdditionalSenseCode)
  1975. break;
  1976. } // end SCSI_SENSE_NOT_READY
  1977. case SCSI_SENSE_MEDIUM_ERROR: { // 0x03
  1978. error = ERROR_CRC;
  1979. retry = FALSE;
  1980. //
  1981. // Check if this error is due to unknown format
  1982. //
  1983. if (asc == SCSI_ADSENSE_INVALID_MEDIA) {
  1984. switch (ascq) {
  1985. case SCSI_SENSEQ_UNKNOWN_FORMAT: {
  1986. error = ERROR_UNRECOGNIZED_MEDIA;
  1987. break;
  1988. }
  1989. case SCSI_SENSEQ_CLEANING_CARTRIDGE_INSTALLED: {
  1990. error = ERROR_UNRECOGNIZED_MEDIA;
  1991. //error = ERROR_CLEANER_CARTRIDGE_INSTALLED;
  1992. break;
  1993. }
  1994. } // end switch AdditionalSenseCodeQualifier
  1995. } // end SCSI_ADSENSE_INVALID_MEDIA
  1996. break;
  1997. } // end SCSI_SENSE_MEDIUM_ERROR
  1998. case SCSI_SENSE_ILLEGAL_REQUEST: { // 0x05
  1999. error = ERROR_INVALID_FUNCTION;
  2000. retry = FALSE;
  2001. switch (asc) {
  2002. case SCSI_ADSENSE_ILLEGAL_BLOCK: {
  2003. error = ERROR_SECTOR_NOT_FOUND;
  2004. break;
  2005. }
  2006. case SCSI_ADSENSE_INVALID_LUN: {
  2007. error = ERROR_FILE_NOT_FOUND;
  2008. break;
  2009. }
  2010. case SCSI_ADSENSE_COPY_PROTECTION_FAILURE: {
  2011. error = ERROR_FILE_ENCRYPTED;
  2012. //error = ERROR_SPT_LIB_COPY_PROTECTION_FAILURE;
  2013. switch (ascq) {
  2014. case SCSI_SENSEQ_AUTHENTICATION_FAILURE:
  2015. //error = ERROR_SPT_LIB_AUTHENTICATION_FAILURE;
  2016. break;
  2017. case SCSI_SENSEQ_KEY_NOT_PRESENT:
  2018. //error = ERROR_SPT_LIB_KEY_NOT_PRESENT;
  2019. break;
  2020. case SCSI_SENSEQ_KEY_NOT_ESTABLISHED:
  2021. //error = ERROR_SPT_LIB_KEY_NOT_ESTABLISHED;
  2022. break;
  2023. case SCSI_SENSEQ_READ_OF_SCRAMBLED_SECTOR_WITHOUT_AUTHENTICATION:
  2024. //error = ERROR_SPT_LIB_SCRAMBLED_SECTOR;
  2025. break;
  2026. case SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT:
  2027. //error = ERROR_SPT_LIB_REGION_MISMATCH;
  2028. break;
  2029. case SCSI_SENSEQ_LOGICAL_UNIT_RESET_COUNT_ERROR:
  2030. //error = ERROR_SPT_LIB_RESETS_EXHAUSTED;
  2031. break;
  2032. } // end switch of ASCQ for COPY_PROTECTION_FAILURE
  2033. break;
  2034. }
  2035. } // end switch (senseBuffer->AdditionalSenseCode)
  2036. break;
  2037. } // end SCSI_SENSE_ILLEGAL_REQUEST
  2038. case SCSI_SENSE_DATA_PROTECT: { // 0x07
  2039. error = ERROR_WRITE_PROTECT;
  2040. retry = FALSE;
  2041. break;
  2042. } // end SCSI_SENSE_DATA_PROTECT
  2043. case SCSI_SENSE_BLANK_CHECK: { // 0x08
  2044. error = ERROR_NO_DATA_DETECTED;
  2045. break;
  2046. } // end SCSI_SENSE_BLANK_CHECK
  2047. case SCSI_SENSE_NO_SENSE: { // 0x00
  2048. if (SenseData->IncorrectLength) {
  2049. error = ERROR_INVALID_BLOCK_LENGTH;
  2050. retry = FALSE;
  2051. } else {
  2052. error = ERROR_IO_DEVICE;
  2053. }
  2054. break;
  2055. } // end SCSI_SENSE_NO_SENSE
  2056. case SCSI_SENSE_HARDWARE_ERROR: // 0x04
  2057. case SCSI_SENSE_UNIT_ATTENTION: // 0x06
  2058. case SCSI_SENSE_UNIQUE: // 0x09
  2059. case SCSI_SENSE_COPY_ABORTED: // 0x0A
  2060. case SCSI_SENSE_ABORTED_COMMAND: // 0x0B
  2061. case SCSI_SENSE_EQUAL: // 0x0C
  2062. case SCSI_SENSE_VOL_OVERFLOW: // 0x0D
  2063. case SCSI_SENSE_MISCOMPARE: // 0x0E
  2064. case SCSI_SENSE_RESERVED: // 0x0F
  2065. default: {
  2066. error = ERROR_IO_DEVICE;
  2067. break;
  2068. }
  2069. } // end switch(SenseKey)
  2070. SetAndExit:
  2071. if (ARGUMENT_PRESENT(SuggestRetry)) {
  2072. *SuggestRetry = retry;
  2073. }
  2074. if (ARGUMENT_PRESENT(SuggestRetryDelay)) {
  2075. *SuggestRetryDelay = retryDelay;
  2076. }
  2077. *ErrorValue = error;
  2078. return;
  2079. }