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.

2405 lines
67 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. cdp.c
  5. Abstract:
  6. A user mode app that allows simple commands to be sent to a
  7. selected scsi device.
  8. Environment:
  9. User mode only
  10. Revision History:
  11. 03-26-96 : Created
  12. --*/
  13. //
  14. // this module may be compiled at warning level 4 with the following
  15. // warnings disabled:
  16. //
  17. #pragma warning(disable:4200) // array[0]
  18. #pragma warning(disable:4201) // nameless struct/unions
  19. #pragma warning(disable:4214) // bit fields other than int
  20. #include <string.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <assert.h>
  24. #include <windows.h>
  25. #include <devioctl.h>
  26. #include <ntddscsi.h>
  27. #include <ntddstor.h>
  28. #include <ntddcdrm.h>
  29. #include <ntdddisk.h>
  30. #include <ntddcdvd.h>
  31. #include <ntddmmc.h>
  32. #define _NTSRB_ // to keep srb.h from being included
  33. #include <scsi.h>
  34. #include "sptlib.h"
  35. #include "cmdhelp.h"
  36. #define MAX_IOCTL_INPUT_SIZE 0x040
  37. #define MAX_IOCTL_OUTPUT_SIZE 0x930 // IOCTL_CDROM_RAW_READ is this large
  38. #define MAX_IOCTL_BUFFER_SIZE (max(MAX_IOCTL_INPUT_SIZE, MAX_IOCTL_OUTPUT_SIZE))
  39. // read no more than 64k at a time -- lots of things just don't support it.
  40. #define MAX_READ_SIZE (64 * 1024)
  41. #ifdef DBG
  42. #define dbg(x) x
  43. #define HELP_ME() fprintf(stderr, "Reached line %4d\n", __LINE__)
  44. #else
  45. #define dbg(x) /* x */
  46. #define HELP_ME() /* printf("Reached line %4d\n", __LINE__) */
  47. #endif
  48. #define ARGUMENT_USED(x) (x == NULL)
  49. typedef struct {
  50. char *Name;
  51. char *Description;
  52. DWORD (*Function)(HANDLE device, int argc, char *argv[]);
  53. } COMMAND;
  54. typedef struct {
  55. SCSI_PASS_THROUGH Spt;
  56. char SenseInfoBuffer[18];
  57. char DataBuffer[0]; // Allocate buffer space
  58. // after this
  59. } SPT_WITH_BUFFERS, *PSPT_WITH_BUFFERS;
  60. ////////////////////////////////////////////////////////////////////////////////
  61. #pragma pack(push, 1)
  62. #define MODE_PAGE_MRW 0x2C // cdrom
  63. typedef struct _MRW_MODE_PAGE {
  64. UCHAR PageCode : 6; // 0x2C
  65. UCHAR Reserved : 1;
  66. UCHAR PSBit : 1; // offset 0
  67. UCHAR PageLength; // 0x06 // offset 1
  68. UCHAR Reserved1; // offset 2
  69. UCHAR UseGAA : 1;
  70. UCHAR Reserved2 : 7; // offset 3
  71. UCHAR Reserved3[4]; // offset 4-7
  72. } MRW_MODE_PAGE, *PMRW_MODE_PAGE;
  73. C_ASSERT(sizeof(MRW_MODE_PAGE) == 8);
  74. #pragma pack(pop)
  75. ////////////////////////////////////////////////////////////////////////////////
  76. #define LBA_TO_MSF(Lba,Minutes,Seconds,Frames) \
  77. { \
  78. (Minutes) = (UCHAR)(Lba / (60 * 75)); \
  79. (Seconds) = (UCHAR)((Lba % (60 * 75)) / 75); \
  80. (Frames) = (UCHAR)((Lba % (60 * 75)) % 75); \
  81. }
  82. DWORD ShowMrwProgressCommand(HANDLE device, int argc, char *argv[]);
  83. DWORD FormatMrwCommand(HANDLE device, int argc, char *argv[]);
  84. DWORD DvdReadStructure(HANDLE device, int argc, char *argv[]);
  85. DWORD StartStopCommand(HANDLE device, int argc, char *argv[]);
  86. DWORD TestCommand(HANDLE device, int argc, char *argv[]);
  87. DWORD ReadTOCCommand(HANDLE device, int argc, char *argv[]);
  88. DWORD ReadTOCExCommand(HANDLE device, int argc, char *argv[]);
  89. DWORD ReadCdTextCommand(HANDLE device, int argc, char *argv[]);
  90. DWORD PlayCommand(HANDLE device, int argc, char *argv[]);
  91. DWORD PauseResumeCommand(HANDLE device, int argc, char *argv[]);
  92. DWORD SendCommand(HANDLE device, int argc, char *argv[]);
  93. DWORD IoctlCommand(HANDLE device, int argc, char *argv[]);
  94. DWORD ListCommand(HANDLE device, int argc, char *argv[]);
  95. DWORD DiskGetPartitionInfo( HANDLE device, int argc, char *argv[]);
  96. DWORD FormatErrorCommand(HANDLE device, int argc, char *argv[]);
  97. DWORD ImageDiskCommand(HANDLE device, int argc, char *argv[]);
  98. DWORD MrwInitTestPatternCommand(HANDLE device, int argc, char *argv[]);
  99. //
  100. // List of commands
  101. // all command names are case sensitive
  102. // arguments are passed into command routines
  103. // list must be terminated with NULL command
  104. // command will not be listed in help if description == NULL
  105. //
  106. COMMAND CommandArray[] = {
  107. {"cdtext", "read cd text info", ReadCdTextCommand},
  108. {"dvdstruct", "Reads a dvd structure from the drive", DvdReadStructure},
  109. {"eject", "spins down and ejects the specified drive", StartStopCommand},
  110. {"error", "provides the error text for a winerror", FormatErrorCommand},
  111. {"help", "help for all commands", ListCommand},
  112. {"ioctl", "ioctl [quoted hex input] [output] sends an arbitrary ioctl", IoctlCommand},
  113. {"image", "<file> images the storage device into the file", ImageDiskCommand},
  114. {"load", "loads the specified drive", StartStopCommand},
  115. {"mrwformat", NULL, FormatMrwCommand},
  116. {"mrwprogress", NULL, ShowMrwProgressCommand},
  117. {"mrwtest", NULL, MrwInitTestPatternCommand},
  118. {"partition", "reads partition information", DiskGetPartitionInfo},
  119. {"pause", "pauses audio playback", PauseResumeCommand},
  120. {"play", "[start track [end track]] plays audio tracks [", PlayCommand},
  121. {"resume", "resumes paused audio playback", PauseResumeCommand},
  122. {"send", NULL, SendCommand},
  123. {"start", "spins up the drive", StartStopCommand},
  124. {"stop", "spinds down the drive", StartStopCommand},
  125. {"test", NULL, TestCommand},
  126. {"toc", "prints the table of contents", ReadTOCCommand},
  127. {"tocex", NULL, ReadTOCExCommand},
  128. // {"tocex", "[Format [Session/Track [MSF]]] Read toc/cdtext/atip/etc.", ReadTOCExCommand},
  129. {NULL, NULL, NULL}
  130. };
  131. #define STATUS_SUCCESS 0
  132. VOID PrintChar( IN UCHAR Char ) {
  133. if ( (Char >= 0x21) && (Char <= 0x7E) ) {
  134. printf("%c", Char);
  135. } else {
  136. printf("%c", '.');
  137. }
  138. }
  139. VOID UpdatePercentageDisplay(IN ULONG Numerator, IN ULONG Denominator) {
  140. ULONG percent;
  141. ULONG i;
  142. if (Numerator > Denominator) {
  143. return;
  144. }
  145. // NOTE: Overflow possibility exists for large numerators.
  146. percent = (Numerator * 100) / Denominator;
  147. for (i=0;i<80;i++) {
  148. putchar('\b');
  149. }
  150. printf("Complete: ");
  151. // each block is 2%
  152. // ----=----1----=----2----=----3----=----4----=----5----=----6----=----7----=----8
  153. // Complete: �.....................
  154. for (i=1; i<100; i+=2) {
  155. if (i < percent) {
  156. putchar(178);
  157. } else if (i == percent) {
  158. putchar(177);
  159. } else {
  160. putchar(176);
  161. }
  162. }
  163. printf(" %d%% (%x/%x)", percent, Numerator, Denominator);
  164. }
  165. int __cdecl main(int argc, char *argv[])
  166. {
  167. int i = 0;
  168. HANDLE h;
  169. char buffer[32];
  170. if(argc < 3) {
  171. printf("Usage: cdp <drive> <command> [parameters]\n");
  172. printf("possible commands: \n");
  173. ListCommand(NULL, argc, argv);
  174. printf("\n");
  175. return -1;
  176. }
  177. sprintf(buffer, "\\\\.\\%s", argv[1]);
  178. dbg(printf("Sending command %s to drive %s\n", argv[2], buffer));
  179. h = CreateFile(buffer,
  180. GENERIC_READ | GENERIC_WRITE,
  181. FILE_SHARE_READ | FILE_SHARE_WRITE,
  182. NULL,
  183. OPEN_EXISTING,
  184. FILE_ATTRIBUTE_NORMAL,
  185. NULL);
  186. if(h == INVALID_HANDLE_VALUE) {
  187. printf("Error %d opening device %s\n", GetLastError(), buffer);
  188. return -2;
  189. }
  190. //
  191. // Iterate through the command array and find the correct function to
  192. // call.
  193. //
  194. while(CommandArray[i].Name != NULL) {
  195. if(strcmp(argv[2], CommandArray[i].Name) == 0) {
  196. (CommandArray[i].Function)(h, (argc - 2), &(argv[2]));
  197. break;
  198. }
  199. i++;
  200. }
  201. if(CommandArray[i].Name == NULL) {
  202. printf("Unknown command %s\n", argv[2]);
  203. }
  204. CloseHandle(h);
  205. return 0;
  206. }
  207. //
  208. // take a PVOID as input -- it's cleaner throughout
  209. //
  210. VOID
  211. PrintBuffer(
  212. IN PVOID InputBuffer,
  213. IN SIZE_T Size
  214. )
  215. {
  216. DWORD offset = 0;
  217. PUCHAR buffer = InputBuffer;
  218. while (Size >= 0x10) {
  219. DWORD i;
  220. printf( "%08x:"
  221. " %02x %02x %02x %02x %02x %02x %02x %02x"
  222. " %02x %02x %02x %02x %02x %02x %02x %02x"
  223. " ",
  224. offset,
  225. *(buffer + 0), *(buffer + 1), *(buffer + 2), *(buffer + 3),
  226. *(buffer + 4), *(buffer + 5), *(buffer + 6), *(buffer + 7),
  227. *(buffer + 8), *(buffer + 9), *(buffer + 10), *(buffer + 11),
  228. *(buffer + 12), *(buffer + 13), *(buffer + 14), *(buffer + 15)
  229. );
  230. for (i=0; i < 0x10; i++) {
  231. PrintChar(*(buffer+i));
  232. }
  233. printf("\n");
  234. Size -= 0x10;
  235. offset += 0x10;
  236. buffer += 0x10;
  237. }
  238. if (Size != 0) {
  239. DWORD i;
  240. printf("%08x:", offset);
  241. //
  242. // print the hex values
  243. //
  244. for (i=0; i<Size; i++) {
  245. if ((i%8)==0) {
  246. printf(" "); // extra space every eight chars
  247. }
  248. printf(" %02x", *(buffer+i));
  249. }
  250. //
  251. // fill in the blanks
  252. //
  253. for (; i < 0x10; i++) {
  254. printf(" ");
  255. }
  256. printf(" ");
  257. //
  258. // print the ascii
  259. //
  260. for (i=0; i<Size; i++) {
  261. PrintChar(*(buffer+i));
  262. }
  263. printf("\n");
  264. }
  265. return;
  266. }
  267. DWORD StartStopCommand(HANDLE device, int argc, char *argv[])
  268. /*++
  269. Routine Description:
  270. Sends down a startstop command.
  271. Arguments:
  272. device - a file handle to send the ioctl to
  273. argc - the number of additional arguments. should be zero
  274. argv[0] - "eject", "load", "start" or "stop"
  275. Return Value:
  276. STATUS_SUCCESS if successful
  277. The value of GetLastError() from the point of failure
  278. --*/
  279. {
  280. DWORD errorValue = STATUS_SUCCESS;
  281. DWORD bufferSize;
  282. CDB cdb;
  283. UCHAR loadEject = 0;
  284. UCHAR start = 0;
  285. UNREFERENCED_PARAMETER(argc);
  286. if(strcmp("eject", argv[0]) == 0) {
  287. loadEject = 1;
  288. start = 0;
  289. } else if(strcmp("load", argv[0]) == 0) {
  290. loadEject = 1;
  291. start = 1;
  292. } else if(strcmp("start", argv[0]) == 0) {
  293. loadEject = 0;
  294. start = 1;
  295. } else if(strcmp("stop", argv[0]) == 0) {
  296. loadEject = 0;
  297. start = 0;
  298. } else {
  299. assert(0);
  300. }
  301. memset(&cdb, 0, sizeof(CDB));
  302. cdb.START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
  303. cdb.START_STOP.Immediate = 0;
  304. cdb.START_STOP.Start = start;
  305. cdb.START_STOP.LoadEject = loadEject;
  306. bufferSize = 0;
  307. if (!SptSendCdbToDevice(device, &cdb, 6, NULL, &bufferSize, FALSE)) {
  308. errorValue = GetLastError();
  309. printf("Eject - error sending IOCTL (%d)\n", errorValue);
  310. }
  311. return errorValue;
  312. }
  313. DWORD ReadCdTextCommand(HANDLE device, int argc, char *argv[])
  314. /*++
  315. Routine Description:
  316. Reads and prints out the cdrom's table of contents,
  317. ATIP, PMA, or CDTEXT data
  318. Arguments:
  319. device - a file handle to send the ioctl to
  320. argc - the number of additional arguments. (1-4 is valid)
  321. argv - the additional arguments
  322. Return Value:
  323. STATUS_SUCCESS if successful
  324. The value of GetLastError() from the point of failure
  325. --*/
  326. {
  327. DWORD returned;
  328. LONG bufferSize = 4; // to get the header
  329. DWORD i;
  330. CDROM_READ_TOC_EX params;
  331. BOOLEAN isText = TRUE;
  332. PUCHAR buffer = NULL;
  333. UNREFERENCED_PARAMETER(argv);
  334. if (argc > 3) {
  335. printf("Too many args\n");
  336. return 1;
  337. }
  338. //
  339. // set defaults - FORMAT_TOC, 0, 0
  340. //
  341. RtlZeroMemory(&params, sizeof(CDROM_READ_TOC_EX));
  342. params.Msf = 0;
  343. params.SessionTrack = 1;
  344. params.Format = 5;
  345. if(argc > 1) params.SessionTrack = (char)atoi(argv[1]);
  346. printf("Session = 0x%x\n", params.SessionTrack);
  347. for (i = 0; i < 2; i++) {
  348. if (i != 0) {
  349. LocalFree(buffer);
  350. }
  351. buffer = LocalAlloc(LPTR, bufferSize);
  352. if (buffer == NULL) {
  353. printf("No Memory %d\n", __LINE__);
  354. return 1;
  355. }
  356. returned = 0;
  357. if (!DeviceIoControl(device,
  358. IOCTL_CDROM_READ_TOC_EX,
  359. &params,
  360. sizeof(CDROM_READ_TOC_EX),
  361. buffer,
  362. bufferSize,
  363. &returned,
  364. FALSE)) {
  365. DWORD errorValue = GetLastError();
  366. LocalFree(buffer);
  367. printf("Eject - error sending IOCTL (%d)\n", errorValue);
  368. return errorValue;
  369. }
  370. bufferSize = (buffer[0] << 8) | (buffer[1]);
  371. bufferSize += 2;
  372. }
  373. if (argc > 2) {
  374. //
  375. // this block is for debugging the various idiosynchracies found
  376. // in CD-TEXT discs. Many discs encode multiple tracks in a single
  377. // block. ie. if one song is called "ABBA", the second "Baby", and
  378. // the third "Longer Name", the Text portion would be encoded as:
  379. // Track 1 'ABBA\0Baby\0Lo'
  380. // Track 3 'nger Name\0'
  381. // This effectively "skips" the name available for Track 2 ?!
  382. // How to work around this....
  383. //
  384. {
  385. HANDLE h;
  386. DWORD temp;
  387. h = CreateFile("OUTPUT.TXT",
  388. GENERIC_WRITE,
  389. 0,
  390. NULL,
  391. CREATE_NEW,
  392. FILE_ATTRIBUTE_NORMAL,
  393. NULL);
  394. if(h == INVALID_HANDLE_VALUE) {
  395. printf("Error %d creating new file \"OUTPUT.TXT\"\n",
  396. GetLastError());
  397. LocalFree(buffer);
  398. return GetLastError();
  399. }
  400. if (!WriteFile(h, buffer, bufferSize, &temp, NULL)) {
  401. printf("Error %d writing file to disk\n", GetLastError());
  402. LocalFree(buffer);
  403. return GetLastError();
  404. }
  405. // continue to output to screen....
  406. }
  407. for (i=0;
  408. FIELD_OFFSET(CDROM_TOC_CD_TEXT_DATA, Descriptors[i+1]) < bufferSize;
  409. i++) {
  410. PCDROM_TOC_CD_TEXT_DATA_BLOCK block;
  411. PCDROM_TOC_CD_TEXT_DATA_BLOCK prevBlock;
  412. DWORD j;
  413. block = (PCDROM_TOC_CD_TEXT_DATA_BLOCK)(buffer + 4);
  414. block += i;
  415. prevBlock = block - 1;
  416. if (block->Unicode) {
  417. continue; // ignore unicode -- this is examplary only
  418. }
  419. for (j=0;j<12;j++) {
  420. // replace NULLs with *, Tabs with hashes
  421. if (block->Text[j] == 0) block->Text[j] = '*';
  422. if (block->Text[j] == 9) block->Text[j] = '#';
  423. }
  424. if (block->SequenceNumber > 0x2b &&
  425. block->SequenceNumber < 0x32) {
  426. UCHAR text[13];
  427. RtlZeroMemory(text, 13);
  428. RtlCopyMemory(text, block->Text, 12);
  429. printf("PackType %02x TrackNo %02x ExtensionFlag %d\n"
  430. "Sequence Number %02x CharacterPosition %02x\n"
  431. "Text: \"%s\"\n\n",
  432. block->PackType,
  433. block->TrackNumber,
  434. block->ExtensionFlag,
  435. block->SequenceNumber,
  436. block->CharacterPosition,
  437. text
  438. );
  439. }
  440. }
  441. printf("\n");
  442. } else {
  443. for (i=0;
  444. FIELD_OFFSET(CDROM_TOC_CD_TEXT_DATA, Descriptors[i+1]) < bufferSize;
  445. i++) {
  446. PCDROM_TOC_CD_TEXT_DATA_BLOCK block;
  447. PCDROM_TOC_CD_TEXT_DATA_BLOCK prevBlock;
  448. DWORD j;
  449. block = (PCDROM_TOC_CD_TEXT_DATA_BLOCK)(buffer + 4);
  450. block += i;
  451. prevBlock = block - 1;
  452. if (block->Unicode) {
  453. continue; // ignore unicode -- this is examplary only
  454. }
  455. //
  456. // set the CRC's to zero so we can hack the data inside to more
  457. // easily handle wierd cases....
  458. //
  459. block->CRC[0] = block->CRC[1] = 0;
  460. //
  461. // set the tab characters to '*' for now.
  462. // i have not yet seen one using this "feature" of cd-text
  463. //
  464. for (j=0;j<12;j++) {
  465. if (block->Text[j] == 9) {
  466. block->Text[j] = '*';
  467. }
  468. }
  469. if ((i != 0) &&
  470. (prevBlock->PackType == block->PackType) &&
  471. (prevBlock->TrackNumber == block->TrackNumber)
  472. ) {
  473. // continuation of previous setting.
  474. } else
  475. if ((!(block->ExtensionFlag)) &&
  476. (block->TrackNumber != 0) &&
  477. (block->TrackNumber == (prevBlock->TrackNumber + 2)) &&
  478. (block->PackType == prevBlock->PackType)
  479. ) {
  480. UCHAR *goodText;
  481. UCHAR *midText;
  482. // printf("\"\n\"HACK DETECTED! (seq %x & %x)",
  483. // prevBlock->SequenceNumber, block->SequenceNumber);
  484. // hack for when prevBlock has two names encoded....
  485. // the TrackNumber/PackType are already equal, just
  486. // move the middle string to the start.
  487. midText = prevBlock->Text;
  488. while (*midText != '\0') {
  489. midText++;
  490. }
  491. midText++;
  492. goodText = prevBlock->Text;
  493. while (*midText != '\0') {
  494. *goodText++ = *midText++;
  495. }
  496. *goodText = '\0';
  497. // printf(" %s", prevBlock->Text);
  498. prevBlock->CharacterPosition = 0;
  499. prevBlock->TrackNumber++;
  500. prevBlock->ExtensionFlag = 1;
  501. i-= 2;
  502. continue; // re-run the previous, modified block
  503. } else {
  504. printf("\"\n");
  505. switch (block->PackType) {
  506. case CDROM_CD_TEXT_PACK_ALBUM_NAME: {
  507. if (block->TrackNumber == 0) {
  508. printf("%-12s", "Album Name");
  509. printf(" : \"");
  510. } else {
  511. printf("%-12s", "Track Name");
  512. printf("(%02d): \"", block->TrackNumber);
  513. }
  514. break;
  515. }
  516. case CDROM_CD_TEXT_PACK_PERFORMER: {
  517. printf("%-12s", "Performer");
  518. printf("(%02d): \"", block->TrackNumber);
  519. break;
  520. }
  521. case CDROM_CD_TEXT_PACK_SONGWRITER: {
  522. printf("%-12s", "Songwriter");
  523. printf("(%02d): \"", block->TrackNumber);
  524. break;
  525. }
  526. case CDROM_CD_TEXT_PACK_COMPOSER: {
  527. printf("%-12s", "Composer");
  528. printf("(%02d): \"", block->TrackNumber);
  529. break;
  530. }
  531. case CDROM_CD_TEXT_PACK_ARRANGER: {
  532. printf("%-12s", "Arranger");
  533. printf("(%02d): \"", block->TrackNumber);
  534. break;
  535. }
  536. case CDROM_CD_TEXT_PACK_MESSAGES: {
  537. printf("%-12s", "Messages");
  538. printf("(%02d): \"", block->TrackNumber);
  539. break;
  540. }
  541. case CDROM_CD_TEXT_PACK_DISC_ID: {
  542. printf("%-12s", "Disc ID");
  543. printf(" : \"");
  544. break;
  545. }
  546. case CDROM_CD_TEXT_PACK_GENRE: {
  547. printf("%-12s", "Genre");
  548. printf("(%02d): \"", block->TrackNumber);
  549. break;
  550. }
  551. case CDROM_CD_TEXT_PACK_UPC_EAN: {
  552. if (block->TrackNumber == 0) {
  553. printf("%-12s", "UPC/EAN");
  554. printf(" : \"");
  555. } else {
  556. printf("%-12s", "ISRC");
  557. printf("(%02d): \"", block->TrackNumber);
  558. }
  559. break;
  560. }
  561. case CDROM_CD_TEXT_PACK_TOC_INFO:
  562. case CDROM_CD_TEXT_PACK_TOC_INFO2:
  563. case CDROM_CD_TEXT_PACK_SIZE_INFO:
  564. default: {
  565. isText = FALSE;
  566. printf("Unknown type 0x%x: \"", block->PackType);
  567. }
  568. } // end switch
  569. //
  570. // have to print previous block's info, if available
  571. //
  572. if (isText && block->CharacterPosition != 0) {
  573. UCHAR text[13];
  574. RtlZeroMemory(text, sizeof(text));
  575. RtlCopyMemory(text,
  576. prevBlock->Text + 12 - block->CharacterPosition,
  577. block->CharacterPosition * sizeof(UCHAR));
  578. printf("%s", text);
  579. }
  580. } // end continuation case
  581. if (isText) {
  582. UCHAR text[13];
  583. RtlZeroMemory(text, sizeof(text));
  584. RtlCopyMemory(text, block->Text, 12);
  585. printf("%s", text);
  586. }
  587. } // end loop through all blocks
  588. printf("\n");
  589. } // end normal printout case
  590. return 0;
  591. }
  592. DWORD ReadTOCExCommand(HANDLE device, int argc, char *argv[])
  593. /*++
  594. Routine Description:
  595. Reads and prints out the cdrom's table of contents,
  596. ATIP, PMA, or CDTEXT data
  597. Arguments:
  598. device - a file handle to send the ioctl to
  599. argc - the number of additional arguments. (1-4 is valid)
  600. argv - the additional arguments
  601. Return Value:
  602. STATUS_SUCCESS if successful
  603. The value of GetLastError() from the point of failure
  604. --*/
  605. {
  606. DWORD returned;
  607. DWORD bufferSize = 4; // to get the header
  608. DWORD i;
  609. CDROM_READ_TOC_EX params;
  610. UNREFERENCED_PARAMETER(argv);
  611. if (argc > 4) {
  612. printf("Too many args\n");
  613. return 1;
  614. }
  615. //
  616. // set defaults - FORMAT_TOC, 0, 0
  617. //
  618. RtlZeroMemory(&params, sizeof(CDROM_READ_TOC_EX));
  619. if(argc > 3) params.Msf = (char)atoi(argv[3]);
  620. if(argc > 2) params.SessionTrack = (char)atoi(argv[2]);
  621. if(argc > 1) params.Format = (char)atoi(argv[1]);
  622. printf("Params.Format = 0x%x\n", params.Format);
  623. printf("Params.SessionTrack = 0x%x\n", params.SessionTrack);
  624. printf("Params.MSF = 0x%x\n", params.Msf);
  625. for (i = 0; i < 2; i++) {
  626. PUCHAR buffer = LocalAlloc(LPTR, bufferSize);
  627. if (buffer == NULL) {
  628. printf("No Memory %d\n", __LINE__);
  629. return 1;
  630. }
  631. returned = 0;
  632. if (!DeviceIoControl(device,
  633. IOCTL_CDROM_READ_TOC_EX,
  634. &params,
  635. sizeof(CDROM_READ_TOC_EX),
  636. buffer,
  637. bufferSize,
  638. &returned,
  639. FALSE)) {
  640. DWORD errorValue = GetLastError();
  641. LocalFree(buffer);
  642. printf("Eject - error sending IOCTL (%d)\n", errorValue);
  643. return errorValue;
  644. }
  645. printf("Successfully got %x bytes:\n", returned);
  646. PrintBuffer(buffer, returned);
  647. bufferSize = (buffer[0] << 8) | (buffer[1]);
  648. LocalFree(buffer);
  649. bufferSize += 2;
  650. printf("Now getting %x bytes:\n", bufferSize);
  651. }
  652. return 0;
  653. }
  654. DWORD ReadTOCCommand(HANDLE device, int argc, char *argv[])
  655. /*++
  656. Routine Description:
  657. Reads and prints out the cdrom's table of contents
  658. Arguments:
  659. device - a file handle to send the ioctl to
  660. argc - the number of additional arguments. should be zero
  661. argv - the additional arguments
  662. Return Value:
  663. STATUS_SUCCESS if successful
  664. The value of GetLastError() from the point of failure
  665. --*/
  666. {
  667. DWORD errorValue = STATUS_SUCCESS;
  668. DWORD returned = 0;
  669. CDB cdb;
  670. CDROM_TOC toc;
  671. int numTracks, i;
  672. PTRACK_DATA track;
  673. UNREFERENCED_PARAMETER(argc);
  674. UNREFERENCED_PARAMETER(argv);
  675. printf("Reading Table of Contents\n");
  676. //
  677. // Get the 4 byte TOC header
  678. //
  679. returned = FIELD_OFFSET(CDROM_TOC, TrackData[0]);
  680. memset(&cdb, 0, sizeof(CDB));
  681. cdb.READ_TOC.OperationCode = SCSIOP_READ_TOC;
  682. cdb.READ_TOC.Msf = 0;
  683. cdb.READ_TOC.StartingTrack = 0;
  684. cdb.READ_TOC.AllocationLength[0] = (UCHAR)(returned >> 8);
  685. cdb.READ_TOC.AllocationLength[1] = (UCHAR)(returned & 0xff);
  686. if (!SptSendCdbToDevice(device, &cdb, 10, (PUCHAR)&toc, &returned, TRUE)) {
  687. errorValue = GetLastError();
  688. printf("Error %d sending READ_TOC pass through\n", errorValue);
  689. return errorValue;
  690. }
  691. dbg(printf("READ_TOC pass through returned %d bytes\n", returned));
  692. numTracks = toc.LastTrack - toc.FirstTrack + 1;
  693. dbg(printf("Getting %d tracks\n", numTracks));
  694. returned =
  695. FIELD_OFFSET(CDROM_TOC, TrackData[0]) +
  696. (numTracks * sizeof(TRACK_DATA));
  697. memset(&cdb, 0, sizeof(CDB));
  698. cdb.READ_TOC.OperationCode = SCSIOP_READ_TOC;
  699. cdb.READ_TOC.Msf = 0;
  700. cdb.READ_TOC.StartingTrack = 1;
  701. cdb.READ_TOC.AllocationLength[0] = (UCHAR)(returned >> 8);
  702. cdb.READ_TOC.AllocationLength[1] = (UCHAR)(returned & 0xff);
  703. if (!SptSendCdbToDevice(device, &cdb, 10, (PUCHAR)&toc, &returned, TRUE)) {
  704. errorValue = GetLastError();
  705. printf("Error %d sending READ_TOC pass through\n", errorValue);
  706. return errorValue;
  707. }
  708. dbg(printf("READ_TOC pass through returned %d bytes\n", returned));
  709. printf("TOC Data Length: %d\n", (toc.Length[0] << 16) | (toc.Length[1]));
  710. printf("First Track Number: %d\n", toc.FirstTrack);
  711. printf("Last Track Number: %d\n", toc.LastTrack);
  712. track = &(toc.TrackData[0]);
  713. printf("Number ADR Control Address (LBA)\n");
  714. printf("------ --- ------- -------------\n");
  715. for(i = 0; i < numTracks; i++) {
  716. DWORD lba =
  717. (track->Address[0] << 24) |
  718. (track->Address[1] << 16) |
  719. (track->Address[2] << 8) |
  720. (track->Address[3] << 0);
  721. UCHAR m,s,f;
  722. LBA_TO_MSF(lba, m, s, f);
  723. printf("%6d %3d %7d %3d:%02d:%02d\n",
  724. track->TrackNumber, track->Adr, track->Control,
  725. m,s,f);
  726. track++;
  727. }
  728. return errorValue;
  729. }
  730. DWORD PlayCommand(HANDLE device, int argc, char *argv[])
  731. /*++
  732. Routine Description:
  733. Plays an audio track
  734. Arguments:
  735. device - a file handle to send the ioctl to
  736. argc - the number of additional arguments.
  737. argv[1] - the starting track. Starts at zero if this is not here
  738. argv[2] - the ending track. Let track if not specified
  739. Return Value:
  740. STATUS_SUCCESS if successful
  741. The value of GetLastError() from the point of failure
  742. --*/
  743. {
  744. UNREFERENCED_PARAMETER(argc);
  745. UNREFERENCED_PARAMETER(argv);
  746. UNREFERENCED_PARAMETER(device);
  747. printf("This command is not implemented\n");
  748. return 1;
  749. }
  750. DWORD PauseResumeCommand(HANDLE device, int argc, char *argv[])
  751. /*++
  752. Routine Description:
  753. pauses or resumes audio playback
  754. Arguments:
  755. device - a file handle to send the ioctl to
  756. argc - the number of additional arguments.
  757. argv[0] - "pause" or "resume"
  758. Return Value:
  759. STATUS_SUCCESS if successful
  760. The value of GetLastError() from the point of failure
  761. --*/
  762. {
  763. DWORD errorValue = STATUS_SUCCESS;
  764. CDB cdb;
  765. char resume;
  766. UNREFERENCED_PARAMETER(argc);
  767. if(strcmp("pause", argv[0]) == 0) {
  768. resume = 0;
  769. } else {
  770. resume = 1;
  771. }
  772. printf("%s cdrom playback\n", (resume ? "Resuming" : "Pausing"));
  773. //
  774. // Unfortunately no one defined the PLAY_INDEX command for us so
  775. // cheat and use MSF
  776. //
  777. memset(&cdb, 0, sizeof(CDB));
  778. cdb.PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
  779. cdb.PAUSE_RESUME.Action = resume;
  780. if (!SptSendCdbToDevice(device, &cdb, 10, NULL, 0, FALSE)) {
  781. errorValue = GetLastError();
  782. printf("Error %d sending PAUSE_RESUME pass through\n", errorValue);
  783. return errorValue;
  784. }
  785. // dbg(printf("PAUSE_RESUME pass through returned %d bytes\n", returned));
  786. return errorValue;
  787. }
  788. DWORD ImageDiskCommand(HANDLE device, int argc, char *argv[])
  789. /*++
  790. Routine Description:
  791. creates an image of the device by reading from sector 0 to N.
  792. Arguments:
  793. device - a file handle to send the ioctl to
  794. argc - the number of additional arguments. should be 2.
  795. argv[1] - the file to output to
  796. Return Value:
  797. STATUS_SUCCESS if successful
  798. The value of GetLastError() from the point of failure
  799. --*/
  800. {
  801. HANDLE file;
  802. PUCHAR buffer;
  803. READ_CAPACITY_DATA capacityData;
  804. ULONG dataSize;
  805. CDB cdb;
  806. ULONG sectorsPerMaxRead;
  807. ULONG currentSector;
  808. if(argc < 2) {
  809. printf("not correct number of args\n");
  810. return -1;
  811. }
  812. printf("Opening file %s\n", argv[1]);
  813. file = CreateFile(argv[1],
  814. GENERIC_WRITE,
  815. 0,
  816. NULL,
  817. CREATE_NEW,
  818. FILE_FLAG_SEQUENTIAL_SCAN,
  819. NULL);
  820. if (file == INVALID_HANDLE_VALUE) {
  821. printf("Error %d creating file %s\n", GetLastError(), argv[1]);
  822. return -2;
  823. }
  824. // read the sector size from the device
  825. RtlZeroMemory(&cdb, sizeof(CDB));
  826. RtlZeroMemory(&capacityData, sizeof(READ_CAPACITY_DATA));
  827. cdb.CDB10.OperationCode = SCSIOP_READ_CAPACITY;
  828. dataSize = sizeof(READ_CAPACITY_DATA);
  829. if (!SptSendCdbToDevice(device, &cdb, 10, (PUCHAR)&capacityData, &dataSize, TRUE)) {
  830. printf("Error %d getting capacity info\n", GetLastError());
  831. return -3;
  832. }
  833. // convert the numbers
  834. PrintBuffer(&capacityData, sizeof(READ_CAPACITY_DATA));
  835. REVERSE_LONG(&capacityData.BytesPerBlock);
  836. REVERSE_LONG(&capacityData.LogicalBlockAddress);
  837. if ( (MAX_READ_SIZE % capacityData.BytesPerBlock) != 0 ) {
  838. printf("Sector size of %x is not power of 2?!\n", capacityData.BytesPerBlock);
  839. // capacityData.BytesPerBlock = 512;
  840. return -5;
  841. }
  842. buffer = (PUCHAR)malloc(MAX_READ_SIZE);
  843. if (!buffer) {
  844. printf("Unable to alloc %x bytes\n", MAX_READ_SIZE);
  845. return -4;
  846. }
  847. sectorsPerMaxRead = MAX_READ_SIZE / capacityData.BytesPerBlock;
  848. // read the data from disk and dump to file
  849. for (currentSector = 0; currentSector < capacityData.LogicalBlockAddress; currentSector += sectorsPerMaxRead) {
  850. ULONG sectorsThisRead = sectorsPerMaxRead;
  851. UpdatePercentageDisplay(currentSector, capacityData.LogicalBlockAddress);
  852. if (currentSector > capacityData.LogicalBlockAddress - sectorsPerMaxRead) {
  853. sectorsThisRead = capacityData.LogicalBlockAddress - sectorsPerMaxRead;
  854. }
  855. RtlZeroMemory(&cdb, sizeof(CDB));
  856. RtlZeroMemory(buffer, MAX_READ_SIZE);
  857. cdb.CDB10.OperationCode = SCSIOP_READ;
  858. cdb.CDB10.LogicalBlockByte0 = (UCHAR)(currentSector >> (8*3));
  859. cdb.CDB10.LogicalBlockByte1 = (UCHAR)(currentSector >> (8*2));
  860. cdb.CDB10.LogicalBlockByte2 = (UCHAR)(currentSector >> (8*1));
  861. cdb.CDB10.LogicalBlockByte3 = (UCHAR)(currentSector >> (8*0));
  862. cdb.CDB10.TransferBlocksMsb = (UCHAR)(sectorsThisRead >> (8*1));
  863. cdb.CDB10.TransferBlocksLsb = (UCHAR)(sectorsThisRead >> (8*0));
  864. dataSize = sectorsThisRead * capacityData.BytesPerBlock;
  865. if (!SptSendCdbToDevice(device, &cdb, 10, buffer, &dataSize, TRUE)) {
  866. printf("Error %d reading %x sectors starting at %x\n",
  867. GetLastError(), sectorsThisRead, currentSector);
  868. free(buffer);
  869. return -6;
  870. }
  871. if (dataSize != sectorsThisRead * capacityData.BytesPerBlock) {
  872. printf("Only got %x of %x bytes reading %x sectors starting at %x\n",
  873. dataSize, sectorsThisRead * capacityData.BytesPerBlock,
  874. sectorsThisRead, currentSector);
  875. free(buffer);
  876. return -7;
  877. }
  878. dataSize = sectorsThisRead * capacityData.BytesPerBlock;
  879. if (!WriteFile(file, buffer, dataSize, &dataSize, NULL)) {
  880. printf("Error %d writing %x bytes starting at sector %x\n",
  881. GetLastError(), dataSize, currentSector);
  882. free(buffer);
  883. return -8;
  884. }
  885. if (dataSize != sectorsThisRead * capacityData.BytesPerBlock) {
  886. printf("Only wrote %x of %x bytes writing %x sectors starting at %x\n",
  887. dataSize, sectorsThisRead * capacityData.BytesPerBlock,
  888. sectorsThisRead, currentSector);
  889. free(buffer);
  890. return -9;
  891. }
  892. }
  893. UpdatePercentageDisplay(currentSector, currentSector);
  894. free(buffer);
  895. printf("\nSuccess!\n");
  896. return 0;
  897. }
  898. DWORD SendCommand(HANDLE device, int argc, char *argv[])
  899. /*++
  900. Routine Description:
  901. Parses a hex byte string and creates a cdb to send down.
  902. Arguments:
  903. device - a file handle to send the ioctl to
  904. argc - the number of additional arguments. should be 2 or 4
  905. argv[1] - The CDB to send in a quoted hex byte string
  906. "47 00 00 00 01 00 00 ff 00 00"
  907. argv[2] - "SET" or "GET"
  908. argv[3] - for GET commands: the number of bytes (decimal) to
  909. expect from the target
  910. for SET commands: a quoted hex byte string to send to
  911. the target
  912. NOTE:
  913. Due to the potentially damaging nature of making sending an
  914. arbitrary SCSI command to an arbitrary device, this command should
  915. not be documented outside of this source code.
  916. Return Value:
  917. STATUS_SUCCESS if successful
  918. The value of GetLastError() from the point of failure
  919. --*/
  920. {
  921. DWORD errorValue = STATUS_SUCCESS;
  922. UCHAR cdbSize;
  923. CDB cdb;
  924. DWORD setData = FALSE;
  925. PUCHAR returnedData = NULL;
  926. DWORD i;
  927. DWORD dataSize = 0;
  928. ////////////////////////////////////////////////////////////////////////////////
  929. // verify the arguments
  930. ////////////////////////////////////////////////////////////////////////////////
  931. if ( argc == 4 ) {
  932. if (strcmp(argv[2], "get") != 0 &&
  933. strcmp(argv[2], "set") != 0 &&
  934. strcmp(argv[2], "GET") != 0 &&
  935. strcmp(argv[2], "SET") != 0 ) {
  936. printf("argv2 == %s\n", argv[2]);
  937. argc = 0; // this will cause help to print
  938. }
  939. if (strcmp(argv[2], "set") == 0 ||
  940. strcmp(argv[2], "SET") == 0 ) {
  941. setData = TRUE;
  942. }
  943. }
  944. if ( argc != 2 && argc != 4 ) {
  945. printf("requires one or three args:\n"
  946. "1)\tquoted hex string for cdb\n"
  947. "2)\t(optional) GET or SET\n"
  948. "3)\t(optional) GET: number of bytes to expect\n"
  949. "\t(optional) SET: quoted hex string for cdb\n");
  950. printf("\n");
  951. printf("Example commands:\n"
  952. "Send STOP_UNIT to eject drive q:\n"
  953. "\tcdp q: send \"1b 00 00 00 02 00\"\n"
  954. "Get CDVD_CAPABILITIES_PAGE from drive q:\n"
  955. "\tcdp q: send \"5a 40 2a 00 00 00 00 00 1a 00\" get 21\n"
  956. );
  957. return 1;
  958. }
  959. ////////////////////////////////////////////////////////////////////////////////
  960. // parse the arguments
  961. ////////////////////////////////////////////////////////////////////////////////
  962. if (!CmdHelpValidateStringHex(argv[1])) {
  963. printf("Hex string must be two (0-9,a-f) then one space (repeated)\n");
  964. return 1;
  965. }
  966. //
  967. // Determine the length of the CDB first
  968. // sscanf returns the number of things read in (ie. cdb size)
  969. //
  970. cdbSize = (UCHAR)sscanf(argv[1],
  971. "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
  972. cdb.AsByte + 0, cdb.AsByte + 1,
  973. cdb.AsByte + 2, cdb.AsByte + 3,
  974. cdb.AsByte + 4, cdb.AsByte + 5,
  975. cdb.AsByte + 6, cdb.AsByte + 7,
  976. cdb.AsByte + 8, cdb.AsByte + 9,
  977. cdb.AsByte + 10, cdb.AsByte + 11,
  978. cdb.AsByte + 12, cdb.AsByte + 13,
  979. cdb.AsByte + 14, cdb.AsByte + 15
  980. );
  981. //
  982. // now figure out how much memory we need to allocate
  983. //
  984. if (argc == 4) {
  985. if (setData) {
  986. if (!CmdHelpValidateStringHexQuoted(argv[3])) {
  987. printf("Hex string must be two (0-9,a-f) then one space (repeated)\n");
  988. return 1;
  989. }
  990. dataSize = strlen(argv[3]);
  991. if (dataSize % 3) {
  992. dataSize /= 3;
  993. dataSize ++;
  994. } else {
  995. dataSize /= 3;
  996. }
  997. if (dataSize == 0) {
  998. printf("Cannot set zero bytes of data\n");
  999. return 1;
  1000. }
  1001. } else {
  1002. i = sscanf(argv[3], "%x", &dataSize);
  1003. if (i != 1) {
  1004. printf("Error scanning second argument\n");
  1005. return 1;
  1006. }
  1007. }
  1008. }
  1009. //
  1010. // allocate the memory we may need
  1011. //
  1012. if (dataSize != 0) {
  1013. returnedData = (PUCHAR)malloc(dataSize);
  1014. if (returnedData == NULL) {
  1015. printf("Unable to allocate %x bytes for data\n", dataSize);
  1016. return 1;
  1017. }
  1018. memset(returnedData, 0, dataSize);
  1019. }
  1020. //
  1021. // now scan in the data to set, if that's what the user wants.
  1022. // note that since it's already been validated, we can presume
  1023. // the format is (number)(number)(space) repeated
  1024. //
  1025. if (setData) {
  1026. ULONG index;
  1027. PCHAR location = argv[3];
  1028. for (index = 0; index < dataSize; index++) {
  1029. if (sscanf(location, "%x", returnedData + index) != 1) {
  1030. printf("sscanf did not return 1 for index %i\n", index);
  1031. return 1;
  1032. }
  1033. if ((*location + 0 == '\0') ||
  1034. (*location + 1 == '\0')) {
  1035. printf("string too short!\n");
  1036. return 1;
  1037. }
  1038. location += 3;
  1039. }
  1040. }
  1041. #if DBG
  1042. ////////////////////////////////////////////////////////////////////////////////
  1043. // provide some user feedback
  1044. ////////////////////////////////////////////////////////////////////////////////
  1045. //
  1046. // it is the amount of data expected back from the command
  1047. //
  1048. printf("\nSending %x byte Command:\n", cdbSize);
  1049. PrintBuffer(cdb.AsByte, cdbSize);
  1050. if (setData) {
  1051. printf("Setting Buffer:\n");
  1052. PrintBuffer(returnedData, dataSize);
  1053. } else {
  1054. printf("Expecting %#x bytes of data\n", dataSize);
  1055. }
  1056. #endif // DBG
  1057. ////////////////////////////////////////////////////////////////////////////////
  1058. // send the command
  1059. ////////////////////////////////////////////////////////////////////////////////
  1060. while (1) {
  1061. UCHAR senseSize = sizeof(SENSE_DATA);
  1062. SENSE_DATA senseData;
  1063. BOOLEAN retry = FALSE;
  1064. DWORD retryDelay = 0;
  1065. if (!SptSendCdbToDeviceEx(device,
  1066. &cdb,
  1067. cdbSize,
  1068. returnedData, &dataSize,
  1069. &senseData, senseSize,
  1070. (BOOLEAN)(setData ? FALSE : TRUE),
  1071. SPT_DEFAULT_TIMEOUT)
  1072. ) {
  1073. errorValue = 0;
  1074. if (senseSize == 0) {
  1075. errorValue = GetLastError();
  1076. if (errorValue == ERROR_SUCCESS) {
  1077. errorValue = ERROR_IO_DEVICE;
  1078. }
  1079. } else {
  1080. printf("Sense Data: (%x bytes) Sense %x ASC %x ASCQ %x\n",
  1081. senseSize,
  1082. senseData.SenseKey & 0xf,
  1083. senseData.AdditionalSenseCode,
  1084. senseData.AdditionalSenseCodeQualifier);
  1085. PrintBuffer(&senseData, senseSize);
  1086. SptUtilInterpretSenseInfo(&senseData,
  1087. senseSize,
  1088. &errorValue,
  1089. &retry,
  1090. &retryDelay);
  1091. }
  1092. if (retry) {
  1093. printf("Command should be retried in %d.%d seconds\n",
  1094. (retryDelay / 10), (retryDelay % 10));
  1095. Sleep(retryDelay*10);
  1096. } else {
  1097. printf("Error %d sending command via pass through\n", errorValue);
  1098. break;
  1099. }
  1100. }
  1101. if (!setData) {
  1102. printf("(%x bytes returned)\n",dataSize);
  1103. PrintBuffer(returnedData, dataSize);
  1104. } else {
  1105. printf("Successfully sent the command\n");
  1106. }
  1107. break; // out of for loop
  1108. }
  1109. return errorValue;
  1110. }
  1111. DWORD TestCommand(HANDLE device, int argc, char *argv[])
  1112. /*++
  1113. Routine Description:
  1114. Tests the command "parsing"
  1115. Arguments:
  1116. device - a file handle to send the ioctl to
  1117. argc - the number of additional arguments. should be zero
  1118. argv - the additional arguments
  1119. Return Value:
  1120. STATUS_SUCCESS if successful
  1121. The value of GetLastError() from the point of failure
  1122. --*/
  1123. {
  1124. int i;
  1125. UNREFERENCED_PARAMETER(device);
  1126. printf("Test - %d additional arguments\n", argc);
  1127. for(i = 0; i < argc; i++) {
  1128. printf("arg %d: %s\n", i, argv[i]);
  1129. }
  1130. return STATUS_SUCCESS;
  1131. }
  1132. DWORD ListCommand(HANDLE device, int argc, char *argv[])
  1133. /*++
  1134. Routine Description:
  1135. Prints out the command list
  1136. Arguments:
  1137. device - unused
  1138. argc - unused
  1139. argv - unused
  1140. Return Value:
  1141. STATUS_SUCCESS
  1142. --*/
  1143. {
  1144. int i = 0;
  1145. UNREFERENCED_PARAMETER(device);
  1146. UNREFERENCED_PARAMETER(argc);
  1147. UNREFERENCED_PARAMETER(argv);
  1148. while(CommandArray[i].Name != NULL) {
  1149. if(CommandArray[i].Description != NULL) {
  1150. printf("\t%s - %s\n",
  1151. CommandArray[i].Name,
  1152. CommandArray[i].Description);
  1153. }
  1154. i++;
  1155. }
  1156. return STATUS_SUCCESS;
  1157. }
  1158. DWORD DvdReadStructure(HANDLE device, int argc, char *argv[])
  1159. /*++
  1160. Routine Description:
  1161. Sends down a startstop command.
  1162. Arguments:
  1163. device - a file handle to send the ioctl to
  1164. argc - the number of additional arguments. should be zero
  1165. argv[0] - "eject", "load", "start" or "stop"
  1166. Return Value:
  1167. STATUS_SUCCESS if successful
  1168. The value of GetLastError() from the point of failure
  1169. --*/
  1170. {
  1171. DVD_READ_STRUCTURE readStructure;
  1172. PUCHAR buffer;
  1173. PDVD_DESCRIPTOR_HEADER header;
  1174. DWORD returned;
  1175. DWORD errorValue = STATUS_SUCCESS;
  1176. printf("argument count is %d\n", argc);
  1177. if(argc <= 1) {
  1178. printf("\tValid structure types are Physical, Copyright, DiskKey, "
  1179. "BCA or Manufacturer\n");
  1180. return STATUS_SUCCESS;
  1181. }
  1182. printf("Argv[1] = %s\n", argv[1]);
  1183. buffer = malloc(sizeof(DVD_DISK_KEY_DESCRIPTOR) +
  1184. sizeof(DVD_DESCRIPTOR_HEADER));
  1185. if (buffer == NULL) {
  1186. printf("Insufficient memory\n");
  1187. return STATUS_SUCCESS;
  1188. }
  1189. header = (PDVD_DESCRIPTOR_HEADER) buffer;
  1190. if(_stricmp("physical", argv[1]) == 0) {
  1191. if(argc < 1) {
  1192. printf("reading physical descriptor requires layer number\n");
  1193. return STATUS_SUCCESS;
  1194. }
  1195. readStructure.Format = DvdPhysicalDescriptor;
  1196. readStructure.LayerNumber = (UCHAR)atoi(argv[1]);
  1197. } else if(_stricmp("copyright", argv[1]) == 0) {
  1198. readStructure.Format = DvdCopyrightDescriptor;
  1199. } else if(_stricmp("diskkey", argv[1]) == 0) {
  1200. if(argc < 1) {
  1201. printf("reading physical descriptor requires a session ID\n");
  1202. return STATUS_SUCCESS;
  1203. }
  1204. readStructure.Format = DvdPhysicalDescriptor;
  1205. readStructure.SessionId = atoi(argv[1]);
  1206. } else if(_stricmp("bca", argv[1]) == 0) {
  1207. readStructure.Format = DvdBCADescriptor;
  1208. } else if(_stricmp("manufacturer", argv[1]) == 0) {
  1209. readStructure.Format = DvdManufacturerDescriptor;
  1210. } else {
  1211. printf("\tValid structure types are Physical, Copyright, DiskKey, "
  1212. "BCA or Manufacturer\n");
  1213. return STATUS_SUCCESS;
  1214. }
  1215. returned = 0;
  1216. if(!DeviceIoControl(device,
  1217. IOCTL_DVD_READ_STRUCTURE,
  1218. &readStructure,
  1219. sizeof(DVD_READ_STRUCTURE),
  1220. buffer,
  1221. sizeof(DVD_DISK_KEY_DESCRIPTOR),
  1222. &returned,
  1223. FALSE)) {
  1224. errorValue = GetLastError();
  1225. printf("Eject - error sending IOCTL (%d)\n", errorValue);
  1226. return errorValue;
  1227. }
  1228. printf("DvdReadStructure returned %d bytes\n", returned);
  1229. printf("Header Length is %#08lx\n", header->Length);
  1230. printf("Header @ %p\n", header);
  1231. printf("Data @ %p\n", &(header->Data[0]));
  1232. if(_stricmp("physical", argv[1]) == 0) {
  1233. PDVD_LAYER_DESCRIPTOR layer = (PDVD_LAYER_DESCRIPTOR) ((PUCHAR) &(header->Data[0]));
  1234. int i;
  1235. printf("\tBook Version: %d\n", layer->BookVersion);
  1236. printf("\tBook Type: %d\n", layer->BookType);
  1237. printf("\tMinimumRate: %d\n", layer->MinimumRate);
  1238. printf("\tDiskSize: %d\n", layer->DiskSize);
  1239. printf("\tLayerType: %d\n", layer->LayerType);
  1240. printf("\tTrackPath: %d\n", layer->TrackPath);
  1241. printf("\tNumberOfLayers: %d\n", layer->NumberOfLayers);
  1242. printf("\tTrackDensity: %d\n", layer->TrackDensity);
  1243. printf("\tLinearDensity: %d\n", layer->LinearDensity);
  1244. printf("\tStartingDataSector: %#08lx\n", layer->StartingDataSector);
  1245. printf("\tEndDataSector: %#08lx\n", layer->EndDataSector);
  1246. printf("\tEndLayerZeroSector: %#08lx\n", layer->EndLayerZeroSector);
  1247. printf("\tBCAFlag: %d\n", layer->BCAFlag);
  1248. printf("\n");
  1249. for(i = 0; i < sizeof(DVD_LAYER_DESCRIPTOR); i++) {
  1250. printf("byte %d: %#x\n", i, header->Data[i]);
  1251. }
  1252. } else if(_stricmp("copyright", argv[1]) == 0) {
  1253. } else if(_stricmp("diskkey", argv[1]) == 0) {
  1254. } else if(_stricmp("bca", argv[1]) == 0) {
  1255. } else if(_stricmp("manufacturer", argv[1]) == 0) {
  1256. }
  1257. printf("final status %d\n", errorValue);
  1258. return errorValue;
  1259. }
  1260. DWORD DiskGetPartitionInfo(HANDLE device, int argc, char *argv[])
  1261. /*++
  1262. Routine Description:
  1263. Sends down a startstop command.
  1264. Arguments:
  1265. device - a file handle to send the ioctl to
  1266. argc - the number of additional arguments. should be zero
  1267. argv[0] - "eject", "load", "start" or "stop"
  1268. Return Value:
  1269. STATUS_SUCCESS if successful
  1270. The value of GetLastError() from the point of failure
  1271. --*/
  1272. {
  1273. PARTITION_INFORMATION partitionInformation;
  1274. DWORD returned;
  1275. DWORD errorValue = STATUS_SUCCESS;
  1276. UNREFERENCED_PARAMETER(argc);
  1277. UNREFERENCED_PARAMETER(argv);
  1278. returned = 0;
  1279. if(!DeviceIoControl(device,
  1280. IOCTL_DISK_GET_PARTITION_INFO,
  1281. NULL,
  1282. 0L,
  1283. &partitionInformation,
  1284. sizeof(PARTITION_INFORMATION),
  1285. &returned,
  1286. FALSE)) {
  1287. errorValue = GetLastError();
  1288. printf("Eject - error sending IOCTL (%d)\n", errorValue);
  1289. return errorValue;
  1290. }
  1291. printf("IOCTL_DISK_GET_PARTITION_INFO returned %d bytes\n", returned);
  1292. printf("Starting Offset = %#016I64x\n", partitionInformation.StartingOffset.QuadPart);
  1293. printf("Partition Length = %#016I64x\n", partitionInformation.PartitionLength.QuadPart);
  1294. printf("Hidden Sectors = %#08lx\n", partitionInformation.HiddenSectors);
  1295. printf("PartitionNumber = %#08lx\n", partitionInformation.PartitionNumber);
  1296. printf("PartitionType = %#08lx\n", partitionInformation.PartitionType);
  1297. printf("BootIndicator = %s\n", partitionInformation.BootIndicator ? "TRUE" : "FALSE");
  1298. printf("RecognizedPartition = %s\n", partitionInformation.RecognizedPartition ? "TRUE" : "FALSE");
  1299. printf("RewritePartition = %s\n", partitionInformation.RewritePartition ? "TRUE" : "FALSE");
  1300. return errorValue;
  1301. }
  1302. DWORD IoctlCommand(HANDLE device, int argc, char *argv[])
  1303. /*++
  1304. Routine Description:
  1305. Sends down a specified ioctl.
  1306. Arguments:
  1307. device - a file handle to send the ioctl to
  1308. argc - the number of additional arguments. should be two
  1309. argv[0] - ioctl code in hexadecimal
  1310. argv[1] - quoted string, bytes to send, "" if none
  1311. argv[2] - number of bytes to get back [optional]
  1312. Return Value:
  1313. STATUS_SUCCESS if successful
  1314. The value of GetLastError() from the point of failure
  1315. --*/
  1316. {
  1317. ULONG ctlCode = 0;
  1318. ULONG returned;
  1319. ULONG inputSize = 0;
  1320. ULONG outputSize = 0;
  1321. UCHAR buffer[MAX_IOCTL_BUFFER_SIZE];
  1322. BOOLEAN get;
  1323. if (argc < 3) { // n+1 -- require two args, accept three
  1324. ctlCode = 0;
  1325. } else if (!CmdHelpValidateStringHexQuoted(argv[2])) {
  1326. printf("input hex string invalid\n");
  1327. ctlCode = 0;
  1328. } else {
  1329. //
  1330. // retrieve the ioctl
  1331. //
  1332. (void)sscanf(argv[1], "%x", &ctlCode);
  1333. }
  1334. if (argc > 3) { // n+1 -- require three args.
  1335. (void)sscanf(argv[3], "%x", &outputSize);
  1336. printf("output size: %x\n", outputSize);
  1337. } else {
  1338. outputSize = 0;
  1339. }
  1340. if (outputSize > MAX_IOCTL_OUTPUT_SIZE) {
  1341. printf("output size too large\n");
  1342. ctlCode = 0;
  1343. }
  1344. if (ctlCode == 0) {
  1345. printf("args:\n"
  1346. "1)\tioctl in hex\n"
  1347. "2)\tquoted string of bytes to send, \"\" if none\n"
  1348. "3)\tnumber of bytes to expect\n");
  1349. return -1;
  1350. }
  1351. //////////////////////////////////////////////////////////////////////////
  1352. // ioctl and args are valid.
  1353. //
  1354. RtlZeroMemory(buffer, sizeof(UCHAR)*MAX_IOCTL_BUFFER_SIZE);
  1355. if (strlen(argv[2])) {
  1356. inputSize = MAX_IOCTL_INPUT_SIZE;
  1357. if (!CmdHelpScanQuotedHexString(argv[2], buffer, &inputSize)) {
  1358. printf("Error scanning hex string\n");
  1359. return -1;
  1360. }
  1361. } else {
  1362. inputSize = 0;
  1363. }
  1364. // inputSize of zero is valid as input
  1365. printf("Sending ioctl %x to device %p\n"
  1366. "using input buffer %p of size %x\n"
  1367. "and output buffer %p of size %x\n",
  1368. ctlCode, device,
  1369. ((inputSize == 0) ? NULL : buffer),
  1370. inputSize,
  1371. ((outputSize == 0) ? NULL : buffer),
  1372. outputSize);
  1373. if (!DeviceIoControl(device,
  1374. ctlCode,
  1375. ((inputSize == 0) ? NULL : buffer),
  1376. inputSize,
  1377. ((outputSize == 0) ? NULL : buffer),
  1378. outputSize,
  1379. &returned,
  1380. FALSE)) {
  1381. printf("Failed with %d\n", GetLastError());
  1382. return GetLastError();
  1383. }
  1384. if (returned != 0) {
  1385. printf("Returned data (%x of %x bytes):\n", returned, outputSize);
  1386. PrintBuffer(buffer, returned);
  1387. } else {
  1388. printf("Command completed successfully\n");
  1389. }
  1390. return 0;
  1391. }
  1392. DWORD FormatErrorCommand(HANDLE device, int argc, char *argv[])
  1393. /*++
  1394. Routine Description:
  1395. Gets and displays the message string associated with an error code.
  1396. Arguments:
  1397. device - not used, but required :P
  1398. argc - the number of additional arguments. should be one
  1399. argv[0] - error code in hexadecimal
  1400. Return Value:
  1401. STATUS_SUCCESS if successful
  1402. The value of GetLastError() from the point of failure
  1403. --*/
  1404. {
  1405. LPVOID stringBuffer = NULL;
  1406. DWORD errorCode = 0x80030306;
  1407. DWORD numOfChars = 0;
  1408. DWORD flags;
  1409. flags = 0;
  1410. flags |= FORMAT_MESSAGE_ALLOCATE_BUFFER;
  1411. flags |= FORMAT_MESSAGE_FROM_SYSTEM;
  1412. flags |= FORMAT_MESSAGE_IGNORE_INSERTS;
  1413. numOfChars = FormatMessageA(flags,
  1414. NULL,
  1415. errorCode,
  1416. 0, // language indifferent
  1417. (LPSTR)&stringBuffer, // double pointer
  1418. 0,
  1419. NULL
  1420. );
  1421. if (stringBuffer == NULL) {
  1422. printf("No buffer returned?\n");
  1423. return -1;
  1424. }
  1425. if (numOfChars == 0) {
  1426. printf("Size zero buffer returned?\n");
  1427. return -1;
  1428. }
  1429. printf("ERROR MESSAGE RETURNED:\n");
  1430. printf("%s\n", stringBuffer);
  1431. LocalFree(stringBuffer);
  1432. return 0;
  1433. }
  1434. DWORD FormatMrwCommand(HANDLE device, int argc, char *argv[])
  1435. /*++
  1436. Routine Description:
  1437. Formats an MRW-Compliant drive and shows percentage complete
  1438. Arguments:
  1439. device - drive to format media as MRW in
  1440. argc - the number of additional arguments. should be zero
  1441. Return Value:
  1442. STATUS_SUCCESS if successful
  1443. The value of GetLastError() from the point of failure
  1444. --*/
  1445. {
  1446. #define MRW_FORMAT_BUFFER_SIZE 0xc
  1447. CDB cdb;
  1448. ULONG size = MRW_FORMAT_BUFFER_SIZE;
  1449. UCHAR formatBuffer[MRW_FORMAT_BUFFER_SIZE];
  1450. RtlZeroMemory(&cdb, sizeof(CDB));
  1451. RtlZeroMemory(formatBuffer, size);
  1452. cdb.CDB6FORMAT.OperationCode = SCSIOP_FORMAT_UNIT;
  1453. cdb.CDB6FORMAT.FormatControl = 0x11;
  1454. //formatBuffer[0x0] = 0x00;
  1455. formatBuffer[0x1] = 0x82;
  1456. //formatBuffer[0x2] = 0x00;
  1457. formatBuffer[0x3] = 0x08;
  1458. formatBuffer[0x4] = 0xff; //---vvv
  1459. formatBuffer[0x5] = 0xff; // NumberOfBlocks must be set to 0xffffffff
  1460. formatBuffer[0x6] = 0xff; //
  1461. formatBuffer[0x7] = 0xff; //--^^^^
  1462. formatBuffer[0x8] = 0x90;
  1463. //formatBuffer[0x9] = 0x00;
  1464. //formatBuffer[0xa] = 0x00;
  1465. //formatBuffer[0xb] = 0x00;
  1466. if (!SptSendCdbToDevice(device,
  1467. &cdb,
  1468. 6,
  1469. formatBuffer,
  1470. &size,
  1471. FALSE)) {
  1472. printf("Unable to format, %x\n", GetLastError());
  1473. return -1;
  1474. }
  1475. return ShowMrwProgressCommand(device, argc, argv);
  1476. }
  1477. DWORD ShowMrwProgressCommand(HANDLE device, int argc, char *argv[])
  1478. /*++
  1479. Routine Description:
  1480. Formats an MRW-Compliant drive and shows percentage complete
  1481. Arguments:
  1482. device - drive to format media as MRW in
  1483. argc - the number of additional arguments. should be zero
  1484. Return Value:
  1485. STATUS_SUCCESS if successful
  1486. The value of GetLastError() from the point of failure
  1487. --*/
  1488. {
  1489. CDB cdb;
  1490. SENSE_DATA sense;
  1491. ULONG size;
  1492. ULONG ignoredLoopCount = 0;
  1493. //
  1494. // loop, displaying percentage done.
  1495. //
  1496. ignoredLoopCount = 0;
  1497. while (1) {
  1498. Sleep(100);
  1499. RtlZeroMemory(&cdb, sizeof(CDB));
  1500. RtlZeroMemory(&sense, sizeof(SENSE_DATA));
  1501. size = sizeof(SENSE_DATA);
  1502. cdb.AsByte[0] = SCSIOP_REQUEST_SENSE;
  1503. cdb.AsByte[4] = (UCHAR)(sizeof(SENSE_DATA));
  1504. if (!SptSendCdbToDevice(device,
  1505. &cdb,
  1506. 6,
  1507. (PUCHAR)&sense,
  1508. &size,
  1509. TRUE)) {
  1510. printf("\nUnable to get percentage done! %x\n", GetLastError());
  1511. return -1;
  1512. }
  1513. if (sense.AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY &&
  1514. sense.AdditionalSenseCodeQualifier == SCSI_SENSEQ_FORMAT_IN_PROGRESS &&
  1515. (sense.SenseKeySpecific[0] & 0x80)
  1516. ) {
  1517. ULONG done;
  1518. done =
  1519. ((sense.SenseKeySpecific[0] & 0x7f) << (8*2)) |
  1520. ((sense.SenseKeySpecific[1] & 0xff) << (8*1)) |
  1521. ((sense.SenseKeySpecific[2] & 0xff) << (8*0)) ;
  1522. UpdatePercentageDisplay(done, 0x10000);
  1523. } else {
  1524. ignoredLoopCount++;
  1525. if (ignoredLoopCount > 12) {
  1526. printf("\nSenseData not as expected. Format may have completed?\n");
  1527. return -1;
  1528. }
  1529. // else let it go on
  1530. }
  1531. }
  1532. }
  1533. BOOLEAN
  1534. ModeSelect(
  1535. HANDLE Device,
  1536. PVOID ModePage,
  1537. ULONG ModePageSize
  1538. )
  1539. {
  1540. CDB cdb;
  1541. ULONG tmp;
  1542. ULONG size;
  1543. PMODE_PARAMETER_HEADER10 header;
  1544. tmp = sizeof(MODE_PARAMETER_HEADER10) + ModePageSize;
  1545. header = malloc(tmp);
  1546. if (header == NULL) {
  1547. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1548. return FALSE;
  1549. }
  1550. RtlCopyMemory(header+1, // pointer math
  1551. ModePage,
  1552. ModePageSize);
  1553. RtlZeroMemory(&cdb, sizeof(CDB));
  1554. cdb.MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
  1555. cdb.MODE_SELECT10.PFBit = 1;
  1556. cdb.MODE_SELECT10.ParameterListLength[0] = (UCHAR)(tmp >> (8*1));
  1557. cdb.MODE_SELECT10.ParameterListLength[1] = (UCHAR)(tmp >> (8*0));
  1558. size = tmp;
  1559. if (!SptSendCdbToDevice(Device,
  1560. &cdb,
  1561. 10,
  1562. (PUCHAR)header,
  1563. &size,
  1564. FALSE)) {
  1565. printf("Unable to set mode page %x\n", GetLastError());
  1566. return FALSE;
  1567. }
  1568. return TRUE;
  1569. }
  1570. BOOLEAN
  1571. FillDisk(
  1572. HANDLE Device,
  1573. ULONG Signature
  1574. )
  1575. {
  1576. READ_CAPACITY_DATA capacity;
  1577. ULONG currentLba;
  1578. PULONGLONG data;
  1579. //
  1580. // do a READ_CAPACITY to find the drive's sector size
  1581. // and number of LBAs
  1582. //
  1583. {
  1584. CDB cdb;
  1585. ULONG size;
  1586. RtlZeroMemory(&cdb, sizeof(CDB));
  1587. RtlZeroMemory(&capacity, sizeof(READ_CAPACITY_DATA));
  1588. cdb.CDB10.OperationCode = SCSIOP_READ_CAPACITY;
  1589. size = sizeof(READ_CAPACITY_DATA);
  1590. if (!SptSendCdbToDevice(Device,
  1591. &cdb,
  1592. 10,
  1593. (PUCHAR)&capacity,
  1594. &size,
  1595. TRUE)) {
  1596. printf("Unable to get capacity %x\n", GetLastError());
  1597. return FALSE;
  1598. }
  1599. //
  1600. // convert the numbers
  1601. //
  1602. REVERSE_LONG(&capacity.BytesPerBlock);
  1603. REVERSE_LONG(&capacity.LogicalBlockAddress);
  1604. if ( (capacity.BytesPerBlock % 512) != 0 ) {
  1605. printf("Sector size of %x is not a multiple of 512?!\n", capacity.BytesPerBlock);
  1606. // capacity.BytesPerBlock = 512;
  1607. return FALSE;
  1608. }
  1609. }
  1610. //
  1611. // print for kicks...
  1612. //
  1613. printf(" Bytes Per Block %10d (%8x)\n"
  1614. "Number Of Sectors %10d (%8x)\n",
  1615. capacity.BytesPerBlock,
  1616. capacity.BytesPerBlock,
  1617. capacity.LogicalBlockAddress,
  1618. capacity.LogicalBlockAddress
  1619. );
  1620. //
  1621. // allocate a sector's worth of data
  1622. //
  1623. data = (PLONGLONG)malloc( capacity.BytesPerBlock );
  1624. if (data == NULL) {
  1625. printf("Not enough memory to allocate data\n");
  1626. return FALSE;
  1627. }
  1628. for (currentLba = 0; currentLba <= capacity.LogicalBlockAddress; currentLba++) {
  1629. CDB cdb;
  1630. PULONGLONG t = data;
  1631. ULONG size;
  1632. ULONG iterate = capacity.BytesPerBlock / sizeof(ULONGLONG);
  1633. ULONG j;
  1634. if ((currentLba % 100) == 0) {
  1635. UpdatePercentageDisplay(currentLba, capacity.LogicalBlockAddress);
  1636. }
  1637. // RtlZeroMemory(data, capacity.BytesPerBlock);
  1638. for (j=0; j < iterate ; j++, t++) {
  1639. *t = ((ULONGLONG)Signature) << 32; // signature
  1640. *t += currentLba; // etc.
  1641. }
  1642. //
  1643. // prepare the "write" operation for this sector
  1644. //
  1645. RtlZeroMemory(&cdb, sizeof(CDB));
  1646. cdb.CDB10.OperationCode = SCSIOP_WRITE;
  1647. cdb.CDB10.LogicalBlockByte0 = (UCHAR)(currentLba >> (8*3));
  1648. cdb.CDB10.LogicalBlockByte1 = (UCHAR)(currentLba >> (8*2));
  1649. cdb.CDB10.LogicalBlockByte2 = (UCHAR)(currentLba >> (8*1));
  1650. cdb.CDB10.LogicalBlockByte3 = (UCHAR)(currentLba >> (8*0));
  1651. cdb.CDB10.TransferBlocksMsb = 0;
  1652. cdb.CDB10.TransferBlocksLsb = 1;
  1653. size = capacity.BytesPerBlock;
  1654. if (!SptSendCdbToDevice(Device, &cdb, 10, (PUCHAR)data, &size, FALSE)) {
  1655. printf("Error %d writing sectors at %x\n",
  1656. GetLastError(), currentLba);
  1657. free(data);
  1658. return FALSE;
  1659. }
  1660. }
  1661. UpdatePercentageDisplay(capacity.LogicalBlockAddress, capacity.LogicalBlockAddress);
  1662. free(data);
  1663. data = NULL;
  1664. return TRUE;
  1665. }
  1666. DWORD MrwInitTestPatternCommand(HANDLE device, int argc, char *argv[])
  1667. /*++
  1668. Routine Description:
  1669. Initializes a disk to contain 64-bit numbers that equate to
  1670. the sector's LBA.
  1671. Arguments:
  1672. device - drive to write to...
  1673. argc - the number of additional arguments. should be zero
  1674. Return Value:
  1675. STATUS_SUCCESS if successful
  1676. The value of GetLastError() from the point of failure
  1677. --*/
  1678. {
  1679. MRW_MODE_PAGE savedModePage;
  1680. RtlZeroMemory(&savedModePage, sizeof(MRW_MODE_PAGE));
  1681. savedModePage.PageCode = 0x3f; // illegal value for MODE_SELECT10
  1682. //
  1683. // first use GET_CONFIGURATION to verify that we're
  1684. // actually on an MRW capable device
  1685. //
  1686. {
  1687. #define MRW_FEATURE_DATA_SIZE (sizeof(GET_CONFIGURATION_HEADER)+sizeof(FEATURE_DATA_MRW))
  1688. GET_CONFIGURATION_IOCTL_INPUT input;
  1689. PGET_CONFIGURATION_HEADER header;
  1690. PFEATURE_DATA_MRW mrwFeature;
  1691. UCHAR data[ MRW_FEATURE_DATA_SIZE ];
  1692. DWORD dataSize;
  1693. DWORD expectedSize;
  1694. DWORD feature;
  1695. ULONG size;
  1696. RtlZeroMemory(&input, sizeof(GET_CONFIGURATION_IOCTL_INPUT));
  1697. RtlZeroMemory(&data, MRW_FEATURE_DATA_SIZE);
  1698. input.Feature = FeatureMrw;
  1699. input.RequestType = SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE;
  1700. size = 0;
  1701. if (!DeviceIoControl(device,
  1702. IOCTL_CDROM_GET_CONFIGURATION,
  1703. &input,
  1704. sizeof(GET_CONFIGURATION_IOCTL_INPUT),
  1705. data,
  1706. MRW_FEATURE_DATA_SIZE,
  1707. &size,
  1708. FALSE)) {
  1709. DWORD errorValue = GetLastError();
  1710. printf("error requesting GET_CONFIG data for MRW feature (%d)\n", errorValue);
  1711. return errorValue;
  1712. }
  1713. header = (PGET_CONFIGURATION_HEADER)data;
  1714. mrwFeature = (PFEATURE_DATA_MRW)header->Data;
  1715. expectedSize =
  1716. MRW_FEATURE_DATA_SIZE -
  1717. RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength);
  1718. dataSize =
  1719. (header->DataLength[0] << (8 * 3)) |
  1720. (header->DataLength[1] << (8 * 2)) |
  1721. (header->DataLength[2] << (8 * 1)) |
  1722. (header->DataLength[3] << (8 * 0));
  1723. if ( dataSize < expectedSize ) {
  1724. printf("data size too small -- drive may not support MRW? (%x)\n", expectedSize);
  1725. return -1;
  1726. }
  1727. feature =
  1728. (mrwFeature->Header.FeatureCode[0] << (8 * 1)) |
  1729. (mrwFeature->Header.FeatureCode[1] << (8 * 0));
  1730. if (feature != FeatureMrw) {
  1731. printf("data size too small -- drive may not support MRW? (%x)\n", feature);
  1732. return -1;
  1733. }
  1734. if (!mrwFeature->Write) {
  1735. printf("Drive supports MRW, but as Read-Only\n");
  1736. return -1;
  1737. }
  1738. if (!mrwFeature->Header.Current) {
  1739. printf("Drive supports MRW, but not with the current medium (may need to be formatted MRW first\n");
  1740. return -1;
  1741. }
  1742. } // end verification
  1743. //
  1744. // ensure we're in the correct mode (data area vs. GAA)
  1745. //
  1746. {
  1747. #define MRW_MODE_PAGE_DATA_SIZE (sizeof(MODE_PARAMETER_HEADER10) + sizeof(MRW_MODE_PAGE))
  1748. PMODE_PARAMETER_HEADER10 header;
  1749. PMRW_MODE_PAGE page;
  1750. PUCHAR data [ MRW_MODE_PAGE_DATA_SIZE ];
  1751. CDB cdb;
  1752. ULONG size;
  1753. ULONG t1, t2;
  1754. RtlZeroMemory(&cdb, sizeof(CDB));
  1755. RtlZeroMemory(data, MRW_MODE_PAGE_DATA_SIZE);
  1756. size = MRW_MODE_PAGE_DATA_SIZE;
  1757. cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  1758. cdb.MODE_SENSE10.Dbd = 1;
  1759. cdb.MODE_SENSE10.PageCode = MODE_PAGE_MRW;
  1760. cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR)(MRW_MODE_PAGE_DATA_SIZE >> 8);
  1761. cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR)(MRW_MODE_PAGE_DATA_SIZE & 0xff);
  1762. PrintBuffer(&cdb, 10);
  1763. if (!SptSendCdbToDevice(device,
  1764. &cdb,
  1765. 10,
  1766. (PUCHAR)&data,
  1767. &size,
  1768. TRUE)) {
  1769. printf("Unable to get MRW mode page %x\n", GetLastError());
  1770. // FAKE IT FOR NOW... BUGBUG
  1771. header = (PMODE_PARAMETER_HEADER10)data;
  1772. RtlZeroMemory(data, MRW_MODE_PAGE_DATA_SIZE);
  1773. header->ModeDataLength[0] = 0;
  1774. header->ModeDataLength[1] = 0xE;
  1775. page = (PMRW_MODE_PAGE)(header+1);
  1776. page->PageCode = MODE_PAGE_MRW;
  1777. page->PageLength = 0x6;
  1778. page->UseGAA = 0;
  1779. }
  1780. HELP_ME();
  1781. header = (PMODE_PARAMETER_HEADER10)data;
  1782. t1 = (header->ModeDataLength[0] << (8*1)) |
  1783. (header->ModeDataLength[1] << (8*0)) ;
  1784. t2 = MRW_MODE_PAGE_DATA_SIZE -
  1785. RTL_SIZEOF_THROUGH_FIELD(MODE_PARAMETER_HEADER10, ModeDataLength);
  1786. if (t1 != t2) {
  1787. // size is wrong
  1788. printf("MRW mode page wrong size, %x != %x\n", t1, t2);
  1789. return -1;
  1790. }
  1791. if ((header->BlockDescriptorLength[0] != 0) ||
  1792. (header->BlockDescriptorLength[1] != 0) ) {
  1793. printf("MRW drive force a block descriptor %x %x\n",
  1794. header->BlockDescriptorLength[0],
  1795. header->BlockDescriptorLength[1]);
  1796. return -1;
  1797. }
  1798. page = (PMRW_MODE_PAGE)(header+1); // pointer arithmetic
  1799. if (page->PageCode != MODE_PAGE_MRW) {
  1800. printf("MRW mode page has wrong page code, %x != %x\n",
  1801. page->PageCode, MODE_PAGE_MRW);
  1802. return -1;
  1803. }
  1804. if (page->UseGAA) {
  1805. printf("MRW mode page is set to GAA\n",
  1806. page->PageCode, MODE_PAGE_MRW);
  1807. // ModeSelect()...
  1808. return -1;
  1809. }
  1810. RtlCopyMemory(&savedModePage, page, sizeof(MRW_MODE_PAGE));
  1811. }
  1812. savedModePage.UseGAA = 1;
  1813. if (!ModeSelect(device, &savedModePage, sizeof(MRW_MODE_PAGE))) {
  1814. printf("Unable to set MRW mode page to use GAA (%x)\n", GetLastError());
  1815. return -1;
  1816. }
  1817. if (!FillDisk(device, '\0wrm')) {
  1818. printf("Unable to fill the GAA (%x)\n", GetLastError());
  1819. }
  1820. printf("\nFinished Writing General Application Area!\n");
  1821. savedModePage.UseGAA = 0;
  1822. if (!ModeSelect(device, &savedModePage, sizeof(MRW_MODE_PAGE))) {
  1823. printf("Unable to revert from GAA space -- disc may be unusable! (%x)\n",
  1824. GetLastError());
  1825. return -1;
  1826. }
  1827. if (!FillDisk(device, '\0WRM')) {
  1828. printf("Unable to fill the disc (%x)\n", GetLastError());
  1829. return -1;
  1830. }
  1831. printf("\nFinished Writing Defect-managed Area!\n");
  1832. return 0;
  1833. }