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.

1436 lines
44 KiB

  1. /*--
  2. Copyright (C) Microsoft Corporation, 2000
  3. Module Name:
  4. mmc.c
  5. Abstract:
  6. This file is used to extend cdrom.sys to detect and use mmc-compatible
  7. drives' capabilities more wisely.
  8. Environment:
  9. kernel mode only
  10. Notes:
  11. SCSI Tape, CDRom and Disk class drivers share common routines
  12. that can be found in the CLASS directory (..\ntos\dd\class).
  13. Revision History:
  14. --*/
  15. #include "ntddk.h"
  16. #include "classpnp.h"
  17. #include "cdrom.h"
  18. #include "mmc.tmh"
  19. NTSTATUS
  20. CdRomGetConfiguration(
  21. IN PDEVICE_OBJECT Fdo,
  22. OUT PGET_CONFIGURATION_HEADER *Buffer,
  23. OUT PULONG BytesReturned,
  24. IN FEATURE_NUMBER StartingFeature,
  25. IN ULONG RequestedType
  26. );
  27. VOID
  28. CdRompPrintAllFeaturePages(
  29. IN PGET_CONFIGURATION_HEADER Buffer,
  30. IN ULONG Usable
  31. );
  32. NTSTATUS
  33. CdRomUpdateMmcDriveCapabilitiesCompletion(
  34. IN PDEVICE_OBJECT Unused,
  35. IN PIRP Irp,
  36. IN PDEVICE_OBJECT Fdo
  37. );
  38. VOID
  39. CdRomPrepareUpdateCapabilitiesIrp(
  40. PDEVICE_OBJECT Fdo
  41. );
  42. /*++
  43. NOT DOCUMENTED YET - may be called at up to DISPATCH_LEVEL
  44. if memory is non-paged
  45. PRESUMES ALL DATA IS ACCESSIBLE based on FeatureBuffer
  46. --*/
  47. VOID
  48. CdRomFindProfileInProfiles(
  49. IN PFEATURE_DATA_PROFILE_LIST ProfileHeader,
  50. IN FEATURE_PROFILE_TYPE ProfileToFind,
  51. OUT PBOOLEAN Found
  52. )
  53. {
  54. PFEATURE_DATA_PROFILE_LIST_EX profile;
  55. ULONG numberOfProfiles;
  56. ULONG i;
  57. ASSERT((ProfileHeader->Header.AdditionalLength % 4) == 0);
  58. *Found = FALSE;
  59. numberOfProfiles = ProfileHeader->Header.AdditionalLength / 4;
  60. profile = ProfileHeader->Profiles; // zero-sized array
  61. for (i = 0; i < numberOfProfiles; i++) {
  62. FEATURE_PROFILE_TYPE currentProfile;
  63. currentProfile =
  64. (profile->ProfileNumber[0] << 8) |
  65. (profile->ProfileNumber[1] & 0xff);
  66. if (currentProfile == ProfileToFind) {
  67. *Found = TRUE;
  68. }
  69. profile++;
  70. }
  71. return;
  72. }
  73. /*++
  74. NOT DOCUMENTED YET - may be called at up to DISPATCH_LEVEL
  75. if memory is non-paged
  76. --*/
  77. PVOID
  78. CdRomFindFeaturePage(
  79. IN PGET_CONFIGURATION_HEADER FeatureBuffer,
  80. IN ULONG Length,
  81. IN FEATURE_NUMBER Feature
  82. )
  83. {
  84. PUCHAR buffer;
  85. PUCHAR limit;
  86. if (Length < sizeof(GET_CONFIGURATION_HEADER) + sizeof(FEATURE_HEADER)) {
  87. return NULL;
  88. }
  89. //
  90. // set limit to point to first illegal address
  91. //
  92. limit = (PUCHAR)FeatureBuffer;
  93. limit += Length;
  94. //
  95. // set buffer to point to first page
  96. //
  97. buffer = FeatureBuffer->Data;
  98. //
  99. // loop through each page until we find the requested one, or
  100. // until it's not safe to access the entire feature header
  101. // (if equal, have exactly enough for the feature header)
  102. //
  103. while (buffer + sizeof(FEATURE_HEADER) <= limit) {
  104. PFEATURE_HEADER header = (PFEATURE_HEADER)buffer;
  105. FEATURE_NUMBER thisFeature;
  106. thisFeature =
  107. (header->FeatureCode[0] << 8) |
  108. (header->FeatureCode[1]);
  109. if (thisFeature == Feature) {
  110. PUCHAR temp;
  111. //
  112. // if don't have enough memory to safely access all the feature
  113. // information, return NULL
  114. //
  115. temp = buffer;
  116. temp += sizeof(FEATURE_HEADER);
  117. temp += header->AdditionalLength;
  118. if (temp > limit) {
  119. //
  120. // this means the transfer was cut-off, an insufficiently
  121. // small buffer was given, or other arbitrary error. since
  122. // it's not safe to view the amount of data (even though
  123. // the header is safe) in this feature, pretend it wasn't
  124. // transferred at all...
  125. //
  126. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  127. "Feature %x exists, but not safe to access all its "
  128. "data. returning NULL\n", Feature));
  129. return NULL;
  130. } else {
  131. return buffer;
  132. }
  133. }
  134. if (header->AdditionalLength % 4) {
  135. ASSERT(!"Feature page AdditionalLength field must be integral multiple of 4!\n");
  136. return NULL;
  137. }
  138. buffer += sizeof(FEATURE_HEADER);
  139. buffer += header->AdditionalLength;
  140. }
  141. return NULL;
  142. }
  143. /*++
  144. Private so we can later expose to someone wanting to use a preallocated buffer
  145. --*/
  146. NTSTATUS
  147. CdRompGetConfiguration(
  148. IN PDEVICE_OBJECT Fdo,
  149. IN PGET_CONFIGURATION_HEADER Buffer,
  150. IN ULONG BufferSize,
  151. OUT PULONG ValidBytes,
  152. IN FEATURE_NUMBER StartingFeature,
  153. IN ULONG RequestedType
  154. )
  155. {
  156. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  157. PCDROM_DATA cdData;
  158. SCSI_REQUEST_BLOCK srb;
  159. PCDB cdb;
  160. ULONG_PTR returned;
  161. NTSTATUS status;
  162. PAGED_CODE();
  163. ASSERT(Buffer);
  164. ASSERT(ValidBytes);
  165. *ValidBytes = 0;
  166. returned = 0;
  167. RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
  168. RtlZeroMemory(Buffer, BufferSize);
  169. fdoExtension = Fdo->DeviceExtension;
  170. cdData = (PCDROM_DATA)(fdoExtension->CommonExtension.DriverData);
  171. if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_BAD_GET_CONFIG_SUPPORT)) {
  172. return STATUS_INVALID_DEVICE_REQUEST;
  173. }
  174. srb.TimeOutValue = CDROM_GET_CONFIGURATION_TIMEOUT;
  175. srb.CdbLength = 10;
  176. cdb = (PCDB)srb.Cdb;
  177. cdb->GET_CONFIGURATION.OperationCode = SCSIOP_GET_CONFIGURATION;
  178. cdb->GET_CONFIGURATION.RequestType = (UCHAR)RequestedType;
  179. cdb->GET_CONFIGURATION.StartingFeature[0] = (UCHAR)(StartingFeature >> 8);
  180. cdb->GET_CONFIGURATION.StartingFeature[1] = (UCHAR)(StartingFeature & 0xff);
  181. cdb->GET_CONFIGURATION.AllocationLength[0] = (UCHAR)(BufferSize >> 8);
  182. cdb->GET_CONFIGURATION.AllocationLength[1] = (UCHAR)(BufferSize & 0xff);
  183. status = ClassSendSrbSynchronous(Fdo, &srb, Buffer,
  184. BufferSize, FALSE);
  185. returned = srb.DataTransferLength;
  186. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  187. "CdromGetConfiguration: Status was %x\n", status));
  188. if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) {
  189. //
  190. // if returned more than can be stored in a ULONG, return false
  191. //
  192. if (returned > (ULONG)(-1)) {
  193. return STATUS_UNSUCCESSFUL;
  194. }
  195. ASSERT(returned <= BufferSize);
  196. *ValidBytes = (ULONG)returned;
  197. return STATUS_SUCCESS;
  198. } else {
  199. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  200. "CdromGetConfiguration: failed %x\n", status));
  201. return status;
  202. }
  203. ASSERT(FALSE);
  204. return STATUS_UNSUCCESSFUL;
  205. }
  206. /*++
  207. Allocates buffer with configuration info, returns STATUS_SUCCESS
  208. or an error if one occurred
  209. NOTE: does not handle case where more than 65000 bytes are returned,
  210. which requires multiple calls with different starting feature
  211. numbers.
  212. --*/
  213. NTSTATUS
  214. CdRomGetConfiguration(
  215. IN PDEVICE_OBJECT Fdo,
  216. OUT PGET_CONFIGURATION_HEADER *Buffer,
  217. OUT PULONG BytesReturned,
  218. IN FEATURE_NUMBER StartingFeature,
  219. IN ULONG RequestedType
  220. )
  221. {
  222. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  223. GET_CONFIGURATION_HEADER header; // eight bytes, not a lot
  224. PGET_CONFIGURATION_HEADER buffer;
  225. ULONG returned;
  226. ULONG size;
  227. ULONG i;
  228. NTSTATUS status;
  229. PAGED_CODE();
  230. fdoExtension = Fdo->DeviceExtension;
  231. *Buffer = NULL;
  232. *BytesReturned = 0;
  233. buffer = NULL;
  234. returned = 0;
  235. //
  236. // send the first request down to just get the header
  237. //
  238. status = CdRompGetConfiguration(Fdo, &header, sizeof(header),
  239. &returned, StartingFeature, RequestedType);
  240. if (!NT_SUCCESS(status)) {
  241. return status;
  242. }
  243. //
  244. // now try again, using information returned to allocate
  245. // just enough memory
  246. //
  247. size = header.DataLength[0] << 24 |
  248. header.DataLength[1] << 16 |
  249. header.DataLength[2] << 8 |
  250. header.DataLength[3] << 0 ;
  251. for (i = 0; i < 4; i++) {
  252. //
  253. // the datalength field is the size *following*
  254. // itself, so adjust accordingly
  255. //
  256. size += 4*sizeof(UCHAR);
  257. //
  258. // make sure the size is reasonable
  259. //
  260. if (size <= sizeof(FEATURE_HEADER)) {
  261. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  262. "CdromGetConfiguration: drive reports only %x bytes?\n",
  263. size));
  264. return STATUS_UNSUCCESSFUL;
  265. }
  266. //
  267. // allocate the memory
  268. //
  269. buffer = (PGET_CONFIGURATION_HEADER)
  270. ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  271. size,
  272. CDROM_TAG_FEATURE);
  273. if (buffer == NULL) {
  274. return STATUS_INSUFFICIENT_RESOURCES;
  275. }
  276. //
  277. // send the first request down to just get the header
  278. //
  279. status = CdRompGetConfiguration(Fdo, buffer, size, &returned,
  280. StartingFeature, RequestedType);
  281. if (!NT_SUCCESS(status)) {
  282. ExFreePool(buffer);
  283. return status;
  284. }
  285. if (returned > size) {
  286. ExFreePool(buffer);
  287. return STATUS_INTERNAL_ERROR;
  288. }
  289. returned = buffer->DataLength[0] << 24 |
  290. buffer->DataLength[1] << 16 |
  291. buffer->DataLength[2] << 8 |
  292. buffer->DataLength[3] << 0 ;
  293. returned += 4*sizeof(UCHAR);
  294. if (returned <= size) {
  295. *Buffer = buffer;
  296. *BytesReturned = size; // amount of 'safe' memory
  297. return STATUS_SUCCESS;
  298. }
  299. //
  300. // else retry using the new size....
  301. //
  302. size = returned;
  303. ExFreePool(buffer);
  304. buffer = NULL;
  305. }
  306. //
  307. // it failed after a number of attempts, so just fail.
  308. //
  309. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  310. "CdRomGetConfiguration: Failed %d attempts to get all feature "
  311. "information\n", i));
  312. return STATUS_IO_DEVICE_ERROR;
  313. }
  314. VOID
  315. CdRomIsDeviceMmcDevice(
  316. IN PDEVICE_OBJECT Fdo,
  317. OUT PBOOLEAN IsMmc
  318. )
  319. {
  320. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  321. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  322. PCDROM_DATA cdData = commonExtension->DriverData;
  323. GET_CONFIGURATION_HEADER localHeader;
  324. NTSTATUS status;
  325. ULONG usable;
  326. ULONG size;
  327. ULONG previouslyFailed;
  328. PAGED_CODE();
  329. ASSERT( commonExtension->IsFdo );
  330. *IsMmc = FALSE;
  331. //
  332. // read the registry in case the drive failed previously,
  333. // and a timeout is occurring.
  334. //
  335. previouslyFailed = FALSE;
  336. ClassGetDeviceParameter(fdoExtension,
  337. CDROM_SUBKEY_NAME,
  338. CDROM_NON_MMC_DRIVE_NAME,
  339. &previouslyFailed
  340. );
  341. if (previouslyFailed) {
  342. SET_FLAG(cdData->HackFlags, CDROM_HACK_BAD_GET_CONFIG_SUPPORT);
  343. }
  344. //
  345. // check for the following profiles:
  346. //
  347. // ProfileList
  348. //
  349. status = CdRompGetConfiguration(Fdo,
  350. &localHeader,
  351. sizeof(localHeader),
  352. &usable,
  353. FeatureProfileList,
  354. SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL);
  355. if (status == STATUS_INVALID_DEVICE_REQUEST ||
  356. status == STATUS_NO_MEDIA_IN_DEVICE ||
  357. status == STATUS_IO_DEVICE_ERROR ||
  358. status == STATUS_IO_TIMEOUT) {
  359. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  360. "GetConfiguration Failed (%x), device %p not mmc-compliant\n",
  361. status, Fdo
  362. ));
  363. previouslyFailed = TRUE;
  364. ClassSetDeviceParameter(fdoExtension,
  365. CDROM_SUBKEY_NAME,
  366. CDROM_NON_MMC_DRIVE_NAME,
  367. previouslyFailed
  368. );
  369. return;
  370. } else if (!NT_SUCCESS(status)) {
  371. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
  372. "GetConfiguration Failed, status %x -- defaulting to -ROM\n",
  373. status));
  374. return;
  375. } else if (usable < sizeof(GET_CONFIGURATION_HEADER)) {
  376. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  377. "GetConfiguration Failed, returned only %x bytes!\n", usable));
  378. previouslyFailed = TRUE;
  379. ClassSetDeviceParameter(fdoExtension,
  380. CDROM_SUBKEY_NAME,
  381. CDROM_NON_MMC_DRIVE_NAME,
  382. previouslyFailed
  383. );
  384. return;
  385. }
  386. size = (localHeader.DataLength[0] << 24) |
  387. (localHeader.DataLength[1] << 16) |
  388. (localHeader.DataLength[2] << 8) |
  389. (localHeader.DataLength[3] << 0);
  390. if(size <= 4) {
  391. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  392. "GetConfiguration Failed, claims MMC support but doesn't "
  393. "correctly return config length!\n"));
  394. return;
  395. }
  396. size += 4; // sizeof the datalength fields
  397. #if DBG
  398. {
  399. PGET_CONFIGURATION_HEADER dbgBuffer;
  400. NTSTATUS dbgStatus;
  401. dbgBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  402. (SIZE_T)size,
  403. CDROM_TAG_FEATURE);
  404. if (dbgBuffer != NULL) {
  405. RtlZeroMemory(dbgBuffer, size);
  406. dbgStatus = CdRompGetConfiguration(Fdo, dbgBuffer, size,
  407. &size, FeatureProfileList,
  408. SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL);
  409. if (NT_SUCCESS(dbgStatus)) {
  410. CdRompPrintAllFeaturePages(dbgBuffer, usable);
  411. }
  412. ExFreePool(dbgBuffer);
  413. }
  414. }
  415. #endif // DBG
  416. *IsMmc = TRUE;
  417. return;
  418. }
  419. VOID
  420. CdRompPrintAllFeaturePages(
  421. IN PGET_CONFIGURATION_HEADER Buffer,
  422. IN ULONG Usable
  423. )
  424. {
  425. PFEATURE_HEADER header;
  426. ////////////////////////////////////////////////////////////////////////////////
  427. // items expected to ALWAYS be current
  428. ////////////////////////////////////////////////////////////////////////////////
  429. header = CdRomFindFeaturePage(Buffer, Usable, FeatureProfileList);
  430. if (header != NULL) {
  431. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  432. "CdromGetConfiguration: CurrentProfile %x "
  433. "with %x bytes of data at %p\n",
  434. Buffer->CurrentProfile[0] << 8 |
  435. Buffer->CurrentProfile[1],
  436. Usable, Buffer));
  437. }
  438. header = CdRomFindFeaturePage(Buffer, Usable, FeatureCore);
  439. if (header) {
  440. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  441. "CdromGetConfiguration: %s %s\n",
  442. (header->Current ?
  443. "Currently supports" : "Is able to support"),
  444. "CORE Features"
  445. ));
  446. }
  447. header = CdRomFindFeaturePage(Buffer, Usable, FeatureMorphing);
  448. if (header) {
  449. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  450. "CdromGetConfiguration: %s %s\n",
  451. (header->Current ?
  452. "Currently supports" : "Is able to support"),
  453. "Morphing"
  454. ));
  455. }
  456. header = CdRomFindFeaturePage(Buffer, Usable, FeatureMultiRead);
  457. if (header) {
  458. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  459. "CdromGetConfiguration: %s %s\n",
  460. (header->Current ?
  461. "Currently supports" : "Is able to support"),
  462. "Multi-Read"
  463. ));
  464. }
  465. header = CdRomFindFeaturePage(Buffer, Usable, FeatureRemovableMedium);
  466. if (header) {
  467. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  468. "CdromGetConfiguration: %s %s\n",
  469. (header->Current ?
  470. "Currently supports" : "Is able to support"),
  471. "Removable Medium"
  472. ));
  473. }
  474. header = CdRomFindFeaturePage(Buffer, Usable, FeatureTimeout);
  475. if (header) {
  476. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  477. "CdromGetConfiguration: %s %s\n",
  478. (header->Current ?
  479. "Currently supports" : "Is able to support"),
  480. "Timeouts"
  481. ));
  482. }
  483. header = CdRomFindFeaturePage(Buffer, Usable, FeaturePowerManagement);
  484. if (header) {
  485. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  486. "CdromGetConfiguration: %s %s\n",
  487. (header->Current ?
  488. "Currently supports" : "Is able to support"),
  489. "Power Management"
  490. ));
  491. }
  492. header = CdRomFindFeaturePage(Buffer, Usable, FeatureEmbeddedChanger);
  493. if (header) {
  494. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  495. "CdromGetConfiguration: %s %s\n",
  496. (header->Current ?
  497. "Currently supports" : "Is able to support"),
  498. "Embedded Changer"
  499. ));
  500. }
  501. header = CdRomFindFeaturePage(Buffer, Usable, FeatureLogicalUnitSerialNumber);
  502. if (header) {
  503. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  504. "CdromGetConfiguration: %s %s\n",
  505. (header->Current ?
  506. "Currently supports" : "Is able to support"),
  507. "LUN Serial Number"
  508. ));
  509. }
  510. header = CdRomFindFeaturePage(Buffer, Usable, FeatureMicrocodeUpgrade);
  511. if (header) {
  512. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  513. "CdromGetConfiguration: %s %s\n",
  514. (header->Current ?
  515. "Currently supports" : "Is able to support"),
  516. "Microcode Update"
  517. ));
  518. }
  519. ////////////////////////////////////////////////////////////////////////////////
  520. // items expected not to always be current
  521. ////////////////////////////////////////////////////////////////////////////////
  522. header = CdRomFindFeaturePage(Buffer, Usable, FeatureCDAudioAnalogPlay);
  523. if (header) {
  524. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  525. "CdromGetConfiguration: %s %s\n",
  526. (header->Current ?
  527. "Currently supports" : "Is able to support"),
  528. "Analogue CD Audio Operations"
  529. ));
  530. }
  531. header = CdRomFindFeaturePage(Buffer, Usable, FeatureCdRead);
  532. if (header) {
  533. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  534. "CdromGetConfiguration: %s %s\n",
  535. (header->Current ?
  536. "Currently supports" : "Is able to support"),
  537. "reading from CD-ROM/R/RW"
  538. ));
  539. }
  540. header = CdRomFindFeaturePage(Buffer, Usable, FeatureCdMastering);
  541. if (header) {
  542. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  543. "CdromGetConfiguration: %s %s\n",
  544. (header->Current ?
  545. "Currently supports" : "Is able to support"),
  546. "CD Recording (Mastering)"
  547. ));
  548. }
  549. header = CdRomFindFeaturePage(Buffer, Usable, FeatureCdTrackAtOnce);
  550. if (header) {
  551. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  552. "CdromGetConfiguration: %s %s\n",
  553. (header->Current ?
  554. "Currently supports" : "Is able to support"),
  555. "CD Recording (Track At Once)"
  556. ));
  557. }
  558. header = CdRomFindFeaturePage(Buffer, Usable, FeatureDvdCSS);
  559. if (header) {
  560. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  561. "CdromGetConfiguration: %s %s\n",
  562. (header->Current ?
  563. "Currently supports" : "Is able to support"),
  564. "DVD CSS"
  565. ));
  566. }
  567. header = CdRomFindFeaturePage(Buffer, Usable, FeatureDvdRead);
  568. if (header) {
  569. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  570. "CdromGetConfiguration: %s %s\n",
  571. (header->Current ?
  572. "Currently supports" : "Is able to support"),
  573. "DVD Structure Reads"
  574. ));
  575. }
  576. header = CdRomFindFeaturePage(Buffer, Usable, FeatureDvdRecordableWrite);
  577. if (header) {
  578. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  579. "CdromGetConfiguration: %s %s\n",
  580. (header->Current ?
  581. "Currently supports" : "Is able to support"),
  582. "DVD Recording (Mastering)"
  583. ));
  584. }
  585. header = CdRomFindFeaturePage(Buffer, Usable, FeatureDiscControlBlocks);
  586. if (header) {
  587. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  588. "CdromGetConfiguration: %s %s\n",
  589. (header->Current ?
  590. "Currently supports" : "Is able to support"),
  591. "DVD Disc Control Blocks"
  592. ));
  593. }
  594. header = CdRomFindFeaturePage(Buffer, Usable, FeatureFormattable);
  595. if (header) {
  596. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  597. "CdromGetConfiguration: %s %s\n",
  598. (header->Current ?
  599. "Currently supports" : "Is able to support"),
  600. "Formatting"
  601. ));
  602. }
  603. header = CdRomFindFeaturePage(Buffer, Usable, FeatureRandomReadable);
  604. if (header) {
  605. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  606. "CdromGetConfiguration: %s %s\n",
  607. (header->Current ?
  608. "Currently supports" : "Is able to support"),
  609. "Random Reads"
  610. ));
  611. }
  612. header = CdRomFindFeaturePage(Buffer, Usable, FeatureRandomWritable);
  613. if (header) {
  614. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  615. "CdromGetConfiguration: %s %s\n",
  616. (header->Current ?
  617. "Currently supports" : "Is able to support"),
  618. "Random Writes"
  619. ));
  620. }
  621. header = CdRomFindFeaturePage(Buffer, Usable, FeatureRestrictedOverwrite);
  622. if (header) {
  623. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  624. "CdromGetConfiguration: %s %s\n",
  625. (header->Current ?
  626. "Currently supports" : "Is able to support"),
  627. "Restricted Overwrites."
  628. ));
  629. }
  630. header = CdRomFindFeaturePage(Buffer, Usable, FeatureWriteOnce);
  631. if (header) {
  632. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  633. "CdromGetConfiguration: %s %s\n",
  634. (header->Current ?
  635. "Currently supports" : "Is able to support"),
  636. "Write Once Media"
  637. ));
  638. }
  639. header = CdRomFindFeaturePage(Buffer, Usable, FeatureSectorErasable);
  640. if (header) {
  641. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  642. "CdromGetConfiguration: %s %s\n",
  643. (header->Current ?
  644. "Currently supports" : "Is able to support"),
  645. "Sector Erasable Media"
  646. ));
  647. }
  648. header = CdRomFindFeaturePage(Buffer, Usable, FeatureIncrementalStreamingWritable);
  649. if (header) {
  650. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  651. "CdromGetConfiguration: %s %s\n",
  652. (header->Current ?
  653. "Currently supports" : "Is able to support"),
  654. "Incremental Streaming Writing"
  655. ));
  656. }
  657. header = CdRomFindFeaturePage(Buffer, Usable, FeatureRealTimeStreaming);
  658. if (header) {
  659. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  660. "CdromGetConfiguration: %s %s\n",
  661. (header->Current ?
  662. "Currently supports" : "Is able to support"),
  663. "Real-time Streaming Reads"
  664. ));
  665. }
  666. header = CdRomFindFeaturePage(Buffer, Usable, FeatureSMART);
  667. if (header) {
  668. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  669. "CdromGetConfiguration: %s %s\n",
  670. (header->Current ?
  671. "Currently supports" : "Is able to support"),
  672. "S.M.A.R.T."
  673. ));
  674. }
  675. header = CdRomFindFeaturePage(Buffer, Usable, FeatureDefectManagement);
  676. if (header) {
  677. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  678. "CdromGetConfiguration: %s %s\n",
  679. (header->Current ?
  680. "Currently supports" : "Is able to support"),
  681. "defect management"
  682. ));
  683. }
  684. return;
  685. }
  686. NTSTATUS
  687. CdRomUpdateMmcDriveCapabilitiesCompletion(
  688. IN PDEVICE_OBJECT Unused,
  689. IN PIRP Irp,
  690. IN PDEVICE_OBJECT Fdo
  691. )
  692. {
  693. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  694. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  695. PCDROM_DATA cdData = fdoExtension->CommonExtension.DriverData;
  696. PCDROM_MMC_EXTENSION mmcData = &(cdData->Mmc);
  697. PSCSI_REQUEST_BLOCK srb = &(mmcData->CapabilitiesSrb);
  698. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  699. NTSTATUS status = STATUS_UNSUCCESSFUL;
  700. PIRP delayedIrp;
  701. // completion routine should retry as neccessary.
  702. // when success, clear the flag to allow startio to proceed.
  703. // else fail original request when retries are exhausted.
  704. ASSERT(mmcData->CapabilitiesIrp == Irp);
  705. // for now, if succeeded, just print the new pages.
  706. if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
  707. //
  708. // ISSUE-2000/4/20-henrygab - should we try to reallocate if size
  709. // available became larger than what we
  710. // originally allocated? otherwise, it
  711. // is possible (not probable) that we
  712. // would miss the feature. can check
  713. // that by finding out what the last
  714. // feature is in the current group.
  715. //
  716. BOOLEAN retry;
  717. ULONG retryInterval;
  718. //
  719. // Release the queue if it is frozen.
  720. //
  721. if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
  722. ClassReleaseQueue(Fdo);
  723. }
  724. retry = ClassInterpretSenseInfo(
  725. Fdo,
  726. srb,
  727. irpStack->MajorFunction,
  728. 0,
  729. MAXIMUM_RETRIES - ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4),
  730. &status,
  731. &retryInterval);
  732. //
  733. // DATA_OVERRUN is not an error in this case....
  734. //
  735. if (status == STATUS_DATA_OVERRUN) {
  736. status = STATUS_SUCCESS;
  737. }
  738. //
  739. // override verify_volume based on original irp's settings
  740. //
  741. if (TEST_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME) &&
  742. status == STATUS_VERIFY_REQUIRED) {
  743. status = STATUS_IO_DEVICE_ERROR;
  744. retry = TRUE;
  745. }
  746. if (retry && ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4)--) {
  747. LARGE_INTEGER delay;
  748. delay.QuadPart = retryInterval;
  749. delay.QuadPart *= (LONGLONG)1000 * 1000 * 10;
  750. //
  751. // retry the request
  752. //
  753. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
  754. "Not using ClassRetryRequest Yet\n"));
  755. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  756. "Retry update capabilities %p\n", Irp));
  757. CdRomPrepareUpdateCapabilitiesIrp(Fdo);
  758. CdRomRetryRequest(fdoExtension, Irp, retryInterval, TRUE);
  759. //
  760. // ClassRetryRequest(Fdo, Irp, delay);
  761. //
  762. return STATUS_MORE_PROCESSING_REQUIRED;
  763. }
  764. } else {
  765. status = STATUS_SUCCESS;
  766. }
  767. Irp->IoStatus.Status = status;
  768. KeSetEvent(&mmcData->CapabilitiesEvent, IO_CD_ROM_INCREMENT, FALSE);
  769. return STATUS_MORE_PROCESSING_REQUIRED;
  770. }
  771. VOID
  772. CdRomPrepareUpdateCapabilitiesIrp(
  773. PDEVICE_OBJECT Fdo
  774. )
  775. {
  776. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  777. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  778. PCDROM_DATA cdData = fdoExtension->CommonExtension.DriverData;
  779. PCDROM_MMC_EXTENSION mmcData = &(cdData->Mmc);
  780. PIO_STACK_LOCATION nextStack;
  781. PSCSI_REQUEST_BLOCK srb;
  782. PCDB cdb;
  783. ULONG bufferSize;
  784. PIRP irp;
  785. ASSERT(mmcData->UpdateState);
  786. ASSERT(mmcData->NumDelayedIrps != 0);
  787. ASSERT(mmcData->CapabilitiesIrp != NULL);
  788. ASSERT(mmcData->CapabilitiesMdl != NULL);
  789. ASSERT(mmcData->CapabilitiesBuffer);
  790. ASSERT(mmcData->CapabilitiesBufferSize != 0);
  791. ASSERT(fdoExtension->SenseData);
  792. //
  793. // do *NOT* call IoReuseIrp(), since it would zero out our
  794. // current irp stack location, which we really don't want
  795. // to happen. it would also set the current irp stack location
  796. // to one greater than currently exists (to give max irp usage),
  797. // but we don't want that either, since we use the top irp stack.
  798. //
  799. // IoReuseIrp(mmcData->CapabilitiesIrp, STATUS_UNSUCCESSFUL);
  800. //
  801. irp = mmcData->CapabilitiesIrp;
  802. srb = &(mmcData->CapabilitiesSrb);
  803. cdb = (PCDB)(srb->Cdb);
  804. bufferSize = mmcData->CapabilitiesBufferSize;
  805. //
  806. // zero stuff out
  807. //
  808. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  809. RtlZeroMemory(fdoExtension->SenseData, sizeof(SENSE_DATA));
  810. RtlZeroMemory(mmcData->CapabilitiesBuffer, bufferSize);
  811. //
  812. // setup the srb
  813. //
  814. srb->TimeOutValue = CDROM_GET_CONFIGURATION_TIMEOUT;
  815. srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  816. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  817. srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
  818. srb->SenseInfoBuffer = fdoExtension->SenseData;
  819. srb->DataBuffer = mmcData->CapabilitiesBuffer;
  820. srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
  821. srb->DataTransferLength = mmcData->CapabilitiesBufferSize;
  822. srb->ScsiStatus = 0;
  823. srb->SrbStatus = 0;
  824. srb->NextSrb = NULL;
  825. srb->OriginalRequest = irp;
  826. srb->SrbFlags = fdoExtension->SrbFlags;
  827. srb->CdbLength = 10;
  828. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
  829. SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
  830. //
  831. // setup the cdb
  832. //
  833. cdb->GET_CONFIGURATION.OperationCode = SCSIOP_GET_CONFIGURATION;
  834. cdb->GET_CONFIGURATION.RequestType = SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT;
  835. cdb->GET_CONFIGURATION.StartingFeature[0] = 0;
  836. cdb->GET_CONFIGURATION.StartingFeature[1] = 0;
  837. cdb->GET_CONFIGURATION.AllocationLength[0] = (UCHAR)(bufferSize >> 8);
  838. cdb->GET_CONFIGURATION.AllocationLength[1] = (UCHAR)(bufferSize & 0xff);
  839. //
  840. // setup the irp
  841. //
  842. nextStack = IoGetNextIrpStackLocation(irp);
  843. nextStack->MajorFunction = IRP_MJ_SCSI;
  844. nextStack->Parameters.Scsi.Srb = srb;
  845. irp->MdlAddress = mmcData->CapabilitiesMdl;
  846. irp->AssociatedIrp.SystemBuffer = mmcData->CapabilitiesBuffer;
  847. IoSetCompletionRoutine(irp, CdRomUpdateMmcDriveCapabilitiesCompletion, Fdo,
  848. TRUE, TRUE, TRUE);
  849. return;
  850. }
  851. VOID
  852. CdRomUpdateMmcDriveCapabilities(
  853. IN PDEVICE_OBJECT Fdo,
  854. IN PVOID Context
  855. )
  856. {
  857. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  858. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  859. PCDROM_DATA cdData = fdoExtension->CommonExtension.DriverData;
  860. PCDROM_MMC_EXTENSION mmcData = &(cdData->Mmc);
  861. PIO_STACK_LOCATION thisStack = IoGetCurrentIrpStackLocation(mmcData->CapabilitiesIrp);
  862. PSCSI_REQUEST_BLOCK srb = &(mmcData->CapabilitiesSrb);
  863. NTSTATUS status;
  864. ASSERT(Context == NULL);
  865. //
  866. // NOTE: a remove lock is unneccessary, since the delayed irp
  867. // will have said lock held for itself, preventing a remove.
  868. //
  869. CdRomPrepareUpdateCapabilitiesIrp(Fdo);
  870. ASSERT(thisStack->Parameters.Others.Argument1 == Fdo);
  871. ASSERT(thisStack->Parameters.Others.Argument2 == mmcData->CapabilitiesBuffer);
  872. ASSERT(thisStack->Parameters.Others.Argument3 == &(mmcData->CapabilitiesSrb));
  873. mmcData->WriteAllowed = FALSE; // default to read-only
  874. //
  875. // set max retries, and also allow volume verify override based on
  876. // original (delayed) irp
  877. //
  878. thisStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
  879. //
  880. // send to self... note that SL_OVERRIDE_VERIFY_VOLUME is not required,
  881. // as this is IRP_MJ_INTERNAL_DEVICE_CONTROL
  882. //
  883. IoCallDriver(commonExtension->LowerDeviceObject, mmcData->CapabilitiesIrp);
  884. KeWaitForSingleObject(&mmcData->CapabilitiesEvent,
  885. Executive, KernelMode, FALSE, NULL);
  886. status = mmcData->CapabilitiesIrp->IoStatus.Status;
  887. if (!NT_SUCCESS(status)) {
  888. goto FinishDriveUpdate;
  889. }
  890. //
  891. // we've updated the feature set, so update whether or not reads and writes
  892. // are allowed or not.
  893. //
  894. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  895. "CdRomUpdateMmc => Succeeded "
  896. "--------------------"
  897. "--------------------\n"));
  898. /*++
  899. NOTE: It is important to only use srb->DataTransferLength worth
  900. of data at this point, since the bufferSize is what is
  901. *available* to use, not what was *actually* used.
  902. --*/
  903. #if DBG
  904. CdRompPrintAllFeaturePages(mmcData->CapabilitiesBuffer,
  905. srb->DataTransferLength);
  906. #endif // DBG
  907. //
  908. // update whether or not writes are allowed. this is currently defined
  909. // as requiring TargetDefectManagement and RandomWritable features
  910. //
  911. {
  912. PFEATURE_HEADER defectHeader;
  913. PFEATURE_HEADER writableHeader;
  914. defectHeader = CdRomFindFeaturePage(mmcData->CapabilitiesBuffer,
  915. srb->DataTransferLength,
  916. FeatureDefectManagement);
  917. writableHeader = CdRomFindFeaturePage(mmcData->CapabilitiesBuffer,
  918. srb->DataTransferLength,
  919. FeatureRandomWritable);
  920. if ((defectHeader != NULL) && (writableHeader != NULL) &&
  921. (defectHeader->Current) && (writableHeader->Current)) {
  922. //
  923. // this should be the *ONLY* place writes are set to allowed
  924. //
  925. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  926. "CdRomUpdateMmc => Writes *allowed*\n"));
  927. mmcData->WriteAllowed = TRUE;
  928. } else {
  929. if (defectHeader == NULL) {
  930. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  931. "CdRomUpdateMmc => No writes - %s = %s\n",
  932. "defect management", "DNE"));
  933. } else {
  934. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  935. "CdRomUpdateMmc => No writes - %s = %s\n",
  936. "defect management", "Not Current"));
  937. }
  938. if (writableHeader == NULL) {
  939. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  940. "CdRomUpdateMmc => No writes - %s = %s\n",
  941. "sector writable", "DNE"));
  942. } else {
  943. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  944. "CdRomUpdateMmc => No writes - %s = %s\n",
  945. "sector writable", "Not Current"));
  946. }
  947. } // end of feature checking
  948. } // end of check for writability
  949. //
  950. // update the cached partition table information
  951. //
  952. // NOTE: THIS WILL CURRENTLY CAUSE A DEADLOCK!
  953. //
  954. // ISSUE-2000/06/20-henrygab - partition support not implemented
  955. // IoReadPartitionTable must be done
  956. // at PASSIVE level, requiring a thread
  957. // or worker item or other such method.
  958. //
  959. #if 0
  960. status = IoReadPartitionTable(Fdo, 1 << fdoExtension->SectorShift,
  961. TRUE, &mmcData->PartitionList);
  962. if (!NT_SUCCESS(status)) {
  963. goto FinishDriveUpdate;
  964. }
  965. #endif
  966. status = STATUS_SUCCESS;
  967. FinishDriveUpdate:
  968. CdRompFlushDelayedList(Fdo, mmcData, status, TRUE);
  969. return;
  970. }
  971. VOID
  972. CdRompFlushDelayedList(
  973. IN PDEVICE_OBJECT Fdo,
  974. IN PCDROM_MMC_EXTENSION MmcData,
  975. IN NTSTATUS Status,
  976. IN BOOLEAN CalledFromWorkItem
  977. )
  978. {
  979. LIST_ENTRY irpList;
  980. PLIST_ENTRY listEntry;
  981. KIRQL oldIrql;
  982. // NOTE - REF #0002
  983. //
  984. // need to set the new state first to prevent deadlocks.
  985. // this is only done from the workitem, to prevent any
  986. // edge cases where we'd "lose" the UpdateRequired
  987. //
  988. // then, must ignore the state, since it's not guaranteed to
  989. // be the same any longer. the only thing left is to handle
  990. // all the delayed irps by flushing the queue and sending them
  991. // back onto the StartIo queue for the device.
  992. //
  993. if (CalledFromWorkItem) {
  994. LONG oldState;
  995. LONG newState;
  996. if (NT_SUCCESS(Status)) {
  997. newState = CdromMmcUpdateComplete;
  998. } else {
  999. newState = CdromMmcUpdateRequired;
  1000. }
  1001. oldState = InterlockedCompareExchange(&MmcData->UpdateState,
  1002. newState,
  1003. CdromMmcUpdateStarted);
  1004. ASSERT(oldState == CdromMmcUpdateStarted);
  1005. } else {
  1006. //
  1007. // just flushing the queue if not called from the workitem,
  1008. // and we don't want to ever fail the queue in those cases.
  1009. //
  1010. ASSERT(NT_SUCCESS(Status));
  1011. }
  1012. /*
  1013. * Get all the delayed IRPs into a private list first to avoid an infinite loop
  1014. * where irps are added to the DelayedIrpsList while we are siphoning them off.
  1015. */
  1016. InitializeListHead(&irpList);
  1017. KeAcquireSpinLock(&MmcData->DelayedIrpsLock, &oldIrql);
  1018. while (!IsListEmpty(&MmcData->DelayedIrpsList)){
  1019. listEntry = RemoveHeadList(&MmcData->DelayedIrpsList);
  1020. InsertTailList(&irpList, listEntry);
  1021. ASSERT(MmcData->NumDelayedIrps > 0);
  1022. MmcData->NumDelayedIrps--;
  1023. }
  1024. ASSERT(MmcData->NumDelayedIrps == 0);
  1025. KeReleaseSpinLock(&MmcData->DelayedIrpsLock, oldIrql);
  1026. // if this assert fires, it means that we have started
  1027. // a workitem when the previous workitem took the delayed
  1028. // irp. if this happens, then the logic in HACKHACK #0002
  1029. // is either flawed or the rules set within are not being
  1030. // followed. this would require investigation.
  1031. ASSERT(!IsListEmpty(&irpList));
  1032. //
  1033. // now either succeed or fail all the delayed irps, according
  1034. // to the update status.
  1035. //
  1036. while (!IsListEmpty(&irpList)){
  1037. PIRP irp;
  1038. listEntry = RemoveHeadList(&irpList);
  1039. irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
  1040. irp->Tail.Overlay.DriverContext[0] = 0;
  1041. irp->Tail.Overlay.DriverContext[1] = 0;
  1042. irp->Tail.Overlay.DriverContext[2] = 0;
  1043. irp->Tail.Overlay.DriverContext[3] = 0;
  1044. if (NT_SUCCESS(Status)) {
  1045. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  1046. "CdRomUpdateMmc => Re-sending delayed irp %p\n",
  1047. irp));
  1048. IoStartPacket(Fdo, irp, NULL, NULL);
  1049. } else {
  1050. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  1051. "CdRomUpdateMmc => Failing delayed irp %p with "
  1052. " status %x\n", irp, Status));
  1053. irp->IoStatus.Information = 0;
  1054. irp->IoStatus.Status = Status;
  1055. ClassReleaseRemoveLock(Fdo, irp);
  1056. IoCompleteRequest(irp, IO_CD_ROM_INCREMENT);
  1057. }
  1058. } // while (list)
  1059. return;
  1060. }
  1061. VOID
  1062. CdRomDeAllocateMmcResources(
  1063. IN PDEVICE_OBJECT Fdo
  1064. )
  1065. {
  1066. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  1067. PCDROM_DATA cddata = commonExtension->DriverData;
  1068. PCDROM_MMC_EXTENSION mmcData = &cddata->Mmc;
  1069. NTSTATUS status;
  1070. if (mmcData->CapabilitiesWorkItem) {
  1071. IoFreeWorkItem(mmcData->CapabilitiesWorkItem);
  1072. mmcData->CapabilitiesWorkItem = NULL;
  1073. }
  1074. if (mmcData->CapabilitiesIrp) {
  1075. IoFreeIrp(mmcData->CapabilitiesIrp);
  1076. mmcData->CapabilitiesIrp = NULL;
  1077. }
  1078. if (mmcData->CapabilitiesMdl) {
  1079. IoFreeMdl(mmcData->CapabilitiesMdl);
  1080. mmcData->CapabilitiesMdl = NULL;
  1081. }
  1082. if (mmcData->CapabilitiesBuffer) {
  1083. ExFreePool(mmcData->CapabilitiesBuffer);
  1084. mmcData->CapabilitiesBuffer = NULL;
  1085. }
  1086. mmcData->CapabilitiesBuffer = 0;
  1087. mmcData->IsMmc = FALSE;
  1088. mmcData->WriteAllowed = FALSE;
  1089. return;
  1090. }
  1091. NTSTATUS
  1092. CdRomAllocateMmcResources(
  1093. IN PDEVICE_OBJECT Fdo
  1094. )
  1095. {
  1096. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  1097. PCDROM_DATA cddata = commonExtension->DriverData;
  1098. PCDROM_MMC_EXTENSION mmcData = &cddata->Mmc;
  1099. PIO_STACK_LOCATION irpStack;
  1100. NTSTATUS status;
  1101. ASSERT(mmcData->CapabilitiesWorkItem == NULL);
  1102. ASSERT(mmcData->CapabilitiesIrp == NULL);
  1103. ASSERT(mmcData->CapabilitiesMdl == NULL);
  1104. ASSERT(mmcData->CapabilitiesBuffer == NULL);
  1105. ASSERT(mmcData->CapabilitiesBufferSize == 0);
  1106. status = CdRomGetConfiguration(Fdo,
  1107. &mmcData->CapabilitiesBuffer,
  1108. &mmcData->CapabilitiesBufferSize,
  1109. FeatureProfileList,
  1110. SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL);
  1111. if (!NT_SUCCESS(status)) {
  1112. ASSERT(mmcData->CapabilitiesBuffer == NULL);
  1113. ASSERT(mmcData->CapabilitiesBufferSize == 0);
  1114. return status;
  1115. }
  1116. ASSERT(mmcData->CapabilitiesBuffer != NULL);
  1117. ASSERT(mmcData->CapabilitiesBufferSize != 0);
  1118. mmcData->CapabilitiesMdl = IoAllocateMdl(mmcData->CapabilitiesBuffer,
  1119. mmcData->CapabilitiesBufferSize,
  1120. FALSE, FALSE, NULL);
  1121. if (mmcData->CapabilitiesMdl == NULL) {
  1122. ExFreePool(mmcData->CapabilitiesBuffer);
  1123. mmcData->CapabilitiesBufferSize = 0;
  1124. return STATUS_INSUFFICIENT_RESOURCES;
  1125. }
  1126. mmcData->CapabilitiesIrp = IoAllocateIrp(Fdo->StackSize + 2, FALSE);
  1127. if (mmcData->CapabilitiesIrp == NULL) {
  1128. IoFreeMdl(mmcData->CapabilitiesMdl);
  1129. ExFreePool(mmcData->CapabilitiesBuffer);
  1130. mmcData->CapabilitiesBufferSize = 0;
  1131. return STATUS_INSUFFICIENT_RESOURCES;
  1132. }
  1133. mmcData->CapabilitiesWorkItem = IoAllocateWorkItem(Fdo);
  1134. if (mmcData->CapabilitiesWorkItem == NULL) {
  1135. IoFreeIrp(mmcData->CapabilitiesIrp);
  1136. IoFreeMdl(mmcData->CapabilitiesMdl);
  1137. ExFreePool(mmcData->CapabilitiesBuffer);
  1138. mmcData->CapabilitiesBufferSize = 0;
  1139. return STATUS_INSUFFICIENT_RESOURCES;
  1140. }
  1141. //
  1142. // everything has been allocated, so now prepare it all....
  1143. //
  1144. MmBuildMdlForNonPagedPool(mmcData->CapabilitiesMdl);
  1145. InitializeListHead(&mmcData->DelayedIrpsList);
  1146. KeInitializeSpinLock(&mmcData->DelayedIrpsLock);
  1147. mmcData->NumDelayedIrps = 0;
  1148. //
  1149. // use the extra stack for internal bookkeeping
  1150. //
  1151. IoSetNextIrpStackLocation(mmcData->CapabilitiesIrp);
  1152. irpStack = IoGetCurrentIrpStackLocation(mmcData->CapabilitiesIrp);
  1153. irpStack->Parameters.Others.Argument1 = Fdo;
  1154. irpStack->Parameters.Others.Argument2 = mmcData->CapabilitiesBuffer;
  1155. irpStack->Parameters.Others.Argument3 = &(mmcData->CapabilitiesSrb);
  1156. // arg 4 is the retry count
  1157. //
  1158. // set the completion event to FALSE for now
  1159. //
  1160. KeInitializeEvent(&mmcData->CapabilitiesEvent,
  1161. SynchronizationEvent, FALSE);
  1162. return STATUS_SUCCESS;
  1163. }