From 25389f86861d6feb65874e9fa2b5371d4aebaf3b Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sun, 13 Oct 2013 01:51:01 +0100 Subject: [PATCH] main() should return something --- FloatUtils.cpp | 118 ++-- FloatUtils.h | 62 +- cdtoimg.cpp | 1774 ++++++++++++++++++++++++------------------------ my_ntddscsi.h | 112 +-- sam.h | 44 +- spc.h | 102 +-- 6 files changed, 1107 insertions(+), 1105 deletions(-) diff --git a/FloatUtils.cpp b/FloatUtils.cpp index 62b0783..b0863ad 100755 --- a/FloatUtils.cpp +++ b/FloatUtils.cpp @@ -1,59 +1,59 @@ -// Floating point utilites -// *********************** -// Round() Rounds a number to a specified number of digits. -// *********************** -// Designed and written by Simon Hughes (shughes@netcomuk.co.uk) -// This code has been fully tested, but should you find any bugs, then please -// let me know. The code is free, but please leave my name and e-mail address intact. -// *********************** -// File: FloatUtils.cpp -// Date: 30th November 1999 -// Notice: If you modify the code in any way and redistribute it, please make a comment. -// *********************** -// Modifications: -// Removed all code except for the Round function. - -#include "FloatUtils.h" -#include - -// Rounds a number to a specified number of digits. -// Number is the number you want to round. -// Num_digits specifies the number of digits to which you want to round number. -// If num_digits is greater than 0, then number is rounded to the specified number of decimal places. -// If num_digits is 0, then number is rounded to the nearest integer. -// Examples -// ROUND(2.15, 1) equals 2.2 -// ROUND(2.149, 1) equals 2.1 -// ROUND(-1.475, 2) equals -1.48 -float Round(const float &number, const int num_digits) -{ - float doComplete5i, doComplete5(number * powf(10.0f, (float) (num_digits + 1))); - - if(number < 0.0f) - doComplete5 -= 5.0f; - else - doComplete5 += 5.0f; - - doComplete5 /= 10.0f; - modff(doComplete5, &doComplete5i); - - return doComplete5i / powf(10.0f, (float) num_digits); -} - -double RoundDouble(double doValue, int nPrecision) -{ - static const double doBase = 10.0; - double doComplete5, doComplete5i; - - doComplete5 = doValue * pow(doBase, (double) (nPrecision + 1)); - - if(doValue < 0.0) - doComplete5 -= 5.0; - else - doComplete5 += 5.0; - - doComplete5 /= doBase; - modf(doComplete5, &doComplete5i); - - return doComplete5i / pow(doBase, (double) nPrecision); -} +// Floating point utilites +// *********************** +// Round() Rounds a number to a specified number of digits. +// *********************** +// Designed and written by Simon Hughes (shughes@netcomuk.co.uk) +// This code has been fully tested, but should you find any bugs, then please +// let me know. The code is free, but please leave my name and e-mail address intact. +// *********************** +// File: FloatUtils.cpp +// Date: 30th November 1999 +// Notice: If you modify the code in any way and redistribute it, please make a comment. +// *********************** +// Modifications: +// Removed all code except for the Round function. + +#include "FloatUtils.h" +#include + +// Rounds a number to a specified number of digits. +// Number is the number you want to round. +// Num_digits specifies the number of digits to which you want to round number. +// If num_digits is greater than 0, then number is rounded to the specified number of decimal places. +// If num_digits is 0, then number is rounded to the nearest integer. +// Examples +// ROUND(2.15, 1) equals 2.2 +// ROUND(2.149, 1) equals 2.1 +// ROUND(-1.475, 2) equals -1.48 +float Round(const float &number, const int num_digits) +{ + float doComplete5i, doComplete5(number * powf(10.0f, (float) (num_digits + 1))); + + if(number < 0.0f) + doComplete5 -= 5.0f; + else + doComplete5 += 5.0f; + + doComplete5 /= 10.0f; + modff(doComplete5, &doComplete5i); + + return doComplete5i / powf(10.0f, (float) num_digits); +} + +double RoundDouble(double doValue, int nPrecision) +{ + static const double doBase = 10.0; + double doComplete5, doComplete5i; + + doComplete5 = doValue * pow(doBase, (double) (nPrecision + 1)); + + if(doValue < 0.0) + doComplete5 -= 5.0; + else + doComplete5 += 5.0; + + doComplete5 /= doBase; + modf(doComplete5, &doComplete5i); + + return doComplete5i / pow(doBase, (double) nPrecision); +} diff --git a/FloatUtils.h b/FloatUtils.h index 50868af..6894a33 100755 --- a/FloatUtils.h +++ b/FloatUtils.h @@ -1,31 +1,31 @@ -// Floating point utilites -// *********************** -// Round() Rounds a number to a specified number of digits. -// *********************** -// Designed and written by Simon Hughes (shughes@netcomuk.co.uk) -// This code has been fully tested, but should you find any bugs, then please -// let me know. The code is free, but please leave my name and e-mail address intact. -// *********************** -// File: FloatUtils.h -// Date: 30th November 1999 -// Notice: If you modify the code in any way and redistribute it, please make a comment. -// *********************** -// Modifications: -// Removed all code except for the Round function. - -#ifndef LocalUtils_h -#define LocalUtils_h - -// Rounds a number to a specified number of digits. -// Number is the number you want to round. -// Num_digits specifies the number of digits to which you want to round number. -// If num_digits is greater than 0, then number is rounded to the specified number of decimal places. -// If num_digits is 0, then number is rounded to the nearest integer. -// Examples -// ROUND(2.15, 1) equals 2.2 -// ROUND(2.149, 1) equals 2.1 -// ROUND(-1.475, 2) equals -1.48 -float Round(const float &number, const int num_digits); -double RoundDouble(double doValue, int nPrecision); - -#endif // LocalUtils_h +// Floating point utilites +// *********************** +// Round() Rounds a number to a specified number of digits. +// *********************** +// Designed and written by Simon Hughes (shughes@netcomuk.co.uk) +// This code has been fully tested, but should you find any bugs, then please +// let me know. The code is free, but please leave my name and e-mail address intact. +// *********************** +// File: FloatUtils.h +// Date: 30th November 1999 +// Notice: If you modify the code in any way and redistribute it, please make a comment. +// *********************** +// Modifications: +// Removed all code except for the Round function. + +#ifndef LocalUtils_h +#define LocalUtils_h + +// Rounds a number to a specified number of digits. +// Number is the number you want to round. +// Num_digits specifies the number of digits to which you want to round number. +// If num_digits is greater than 0, then number is rounded to the specified number of decimal places. +// If num_digits is 0, then number is rounded to the nearest integer. +// Examples +// ROUND(2.15, 1) equals 2.2 +// ROUND(2.149, 1) equals 2.1 +// ROUND(-1.475, 2) equals -1.48 +float Round(const float &number, const int num_digits); +double RoundDouble(double doValue, int nPrecision); + +#endif // LocalUtils_h diff --git a/cdtoimg.cpp b/cdtoimg.cpp index 785eeb9..8449cc3 100755 --- a/cdtoimg.cpp +++ b/cdtoimg.cpp @@ -1,886 +1,888 @@ -/* -CDToImg v1.01. -22 Oct 2006. -Written by Truman. - -Language and type: MS Visual Studio .NET 2002, Visual C++ v7, mixed C and C++, -Application type : Win32 console. - -A program that reads an entire CD-ROM (mode 1 or mode 2 form 1) 2048 bytes per -sector and writes to a file - this would be an .ISO file. The CD must be CD-ROM -mode 1 or mode 2 and non-multisession. Note, it does not check if the CD is -valid. TAO writing mode creates link blocks and this program does not detect -them so if encountered will be considered as a normal sector or unreadable. -Unreadable sectors are not supported and will terminate the process. Only up to -80 minutes reading is supported for the moment. Note that some drives will -ignore certain read speeds, e.g. my Plextor 755A can only be set to a minimum -of 4x read speed. On some drives, reading the last few sectors or ejecting the -disc when reading in 2048 byte/sector mode results in a hang (e.g.: LG CDROM -drive: HL-DT-ST CDROM GCR-8485B 1.05). - -As always I do not take any responsibilities if this tool destroys your drive or -even anything else. - -This code uses: -- Win32 IOCTL function with SCSI_PASS_THROUGH_DIRECT. -- The SCSI codes used in this source were taken from the draft documents MMC1, - SPC1 and SAM1. -- MMC1 Read CD command (0xBE, CDB 12) to read sectors (2048 user bytes mode). -- Determine errors, retrieve and decode a few sense data. - -Normally you need the ntddscsi.h file from Microsoft DDK CD, but I shouldn't -distribute it, so instead I have written my own my_ntddscsi.h. - -If you don't have windows.h some of the define constants are listed as comments. - -This is a Win32 console program and only runs in a DOS prompt under Windows -NT4/2K/XP/2003 with appropriate user rights, i.e. you need to log in as -administrator. - -Read readme.txt for more info. -*/ - -#include -#include -#include -#include "my_ntddscsi.h" -#include "sam.h" -#include "FloatUtils.h" - -//Global variables.. -T_SPDT_SBUF sptd_sb; //Includes sense buffer -unsigned char *data_buf; //Buffer for holding transfer data from or to drive. - -/* - 1. Check the drive type to see if it's identified as a CDROM drive - - 2. Uses Win32 CreateFile function to get a handle to a drive - that is specified by cDriveLetter. - - If you don't have windows.h, some of the define constants are - listed as comments. -*/ -HANDLE open_volume(char drive_letter) -{ - HANDLE hVolume; - UINT uDriveType; - char szVolumeName[8]; - char szRootName[5]; - - //Make drive_letter as a null terminated string in the form of e.g.: d:\. - szRootName[0]=drive_letter; - szRootName[1]=':'; - szRootName[2]='\\'; - szRootName[3]='\0'; - - uDriveType = GetDriveType(szRootName); - - //#define GENERIC_READ 0x80000000L - //#define GENERIC_WRITE 0x40000000L - switch(uDriveType) - { - case DRIVE_CDROM: - { - printf("Drive type is recognised as CDROM/DVD.\n"); - break; - } - default: - { - printf("Drive type is not CDROM/DVD, aborting.\n"); - return INVALID_HANDLE_VALUE; //#define INVALID_HANDLE_VALUE (long int *)-1 - } - } - - //Make drive_letter as a null terminated string in the form of e.g.: \\.\d:. - szVolumeName[0]='\\'; - szVolumeName[1]='\\'; - szVolumeName[2]='.'; - szVolumeName[3]='\\'; - szVolumeName[4]=drive_letter; - szVolumeName[5]=':'; - szVolumeName[6]='\0'; - - //#define FILE_SHARE_READ 0x00000001 - //#define FILE_SHARE_WRITE 0x00000002 - //#define OPEN_EXISTING 3 - //#define FILE_ATTRIBUTE_NORMAL 0x00000080 - //This will only work for CD/DVD device on W2K and higher. - hVolume = CreateFile(szVolumeName, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - - if(hVolume == INVALID_HANDLE_VALUE) - { - //Try again for NT4.. - hVolume = CreateFile(szVolumeName, - GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - - if(hVolume == INVALID_HANDLE_VALUE) - { - printf("Could not create handle for CD/DVD device.\n"); - } - } - - return hVolume; -} - -/* Displays sense error information. */ -void disp_sense() -{ - unsigned char key; - unsigned char ASC; - unsigned char ASCQ; - - key=sptd_sb.SenseBuf[2] & 0x0F; //Sense key is only the lower 4 bits - ASC=sptd_sb.SenseBuf[12]; - ASCQ=sptd_sb.SenseBuf[13]; - - printf("Sense data, key:ASC:ASCQ: %02X:%02X:%02X", key, ASC, ASCQ); - - //Decode sense key:ASC:ASCQ. - //It's a very short list - I'm just trying to show you how to decode into text. - //You really need to look into MMC document and change this into an exhaustive list from - //the sense error table that is found in there. - if(key==SEN_KEY_NO_SEN) - { - if(ASC==0x00) - { - if(ASCQ==0x00) - { - printf(" - No additional sense info."); //No errors - } - } - } - else - if(key==SEN_KEY_NOT_READY) - { - if(ASC==0x3A) - { - if(ASCQ==0x00) - { - printf(" - Medium not present."); - } - else - if(ASCQ==0x01) - { - printf(" - Medium not present-tray closed."); - } - else - if(ASCQ==0x02) - { - printf(" - Medium not present-tray open."); - } - } - } - - printf("\n"); -} - -/* - 1. Set up the sptd values. - 2. Set up the CDB for SPC1 test unit ready command. - 3. Send the request to the drive. -*/ -BOOL test_unit_ready(HANDLE hVolume) -{ - DWORD dwBytesReturned; - - sptd_sb.sptd.Length=sizeof(SCSI_PASS_THROUGH_DIRECT); - sptd_sb.sptd.PathId=0; //SCSI card ID will be filled in automatically. - sptd_sb.sptd.TargetId=0; //SCSI target ID will also be filled in. - sptd_sb.sptd.Lun=0; //SCSI lun ID will also be filled in. - sptd_sb.sptd.CdbLength=6; //CDB size. - sptd_sb.sptd.SenseInfoLength=MAX_SENSE_LEN; //Maximum length of sense data to retrieve. - sptd_sb.sptd.DataIn=SCSI_IOCTL_DATA_UNSPECIFIED; //There will be no buffer data to/from drive. - sptd_sb.sptd.DataTransferLength=0; //Size of buffer transfer data. - sptd_sb.sptd.TimeOutValue=108000; //SCSI timeout value (max 108000 sec = time 30 min). - sptd_sb.sptd.DataBuffer=(PVOID)data_buf; - sptd_sb.sptd.SenseInfoOffset=sizeof(SCSI_PASS_THROUGH_DIRECT); - - //CDB with values for Test Unit Ready CDB6 command. - //The values were taken from SPC1 draft paper. - sptd_sb.sptd.Cdb[0]=0x00; //Code for Test Unit Ready CDB6 command. - sptd_sb.sptd.Cdb[1]=0; - sptd_sb.sptd.Cdb[2]=0; - sptd_sb.sptd.Cdb[3]=0; - sptd_sb.sptd.Cdb[4]=0; - sptd_sb.sptd.Cdb[5]=0; - sptd_sb.sptd.Cdb[6]=0; - sptd_sb.sptd.Cdb[7]=0; - sptd_sb.sptd.Cdb[8]=0; - sptd_sb.sptd.Cdb[9]=0; - sptd_sb.sptd.Cdb[10]=0; - sptd_sb.sptd.Cdb[11]=0; - sptd_sb.sptd.Cdb[12]=0; - sptd_sb.sptd.Cdb[13]=0; - sptd_sb.sptd.Cdb[14]=0; - sptd_sb.sptd.Cdb[15]=0; - - ZeroMemory(sptd_sb.SenseBuf, MAX_SENSE_LEN); - - //Send the command to drive. - return DeviceIoControl(hVolume, - IOCTL_SCSI_PASS_THROUGH_DIRECT, - (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), - (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), - &dwBytesReturned, - NULL); -} - -/* - 1. Set up the sptd values. - 2. Set up the CDB for MMC1 set CD speed command. - 3. Send the request to the drive. -*/ -BOOL set_cd_speed(HANDLE hVolume, - unsigned short int in_read_speed, - unsigned short int in_write_speed) -{ - DWORD dwBytesReturned; - - sptd_sb.sptd.Length=sizeof(SCSI_PASS_THROUGH_DIRECT); - sptd_sb.sptd.PathId=0; //SCSI card ID will be filled in automatically. - sptd_sb.sptd.TargetId=0; //SCSI target ID will also be filled in. - sptd_sb.sptd.Lun=0; //SCSI lun ID will also be filled in. - sptd_sb.sptd.CdbLength=12; //CDB size - sptd_sb.sptd.SenseInfoLength=MAX_SENSE_LEN; //Return sense buffer length. - sptd_sb.sptd.DataIn=SCSI_IOCTL_DATA_UNSPECIFIED; //There will be no buffer data to/from drive. - sptd_sb.sptd.DataTransferLength=0; //Size of buffer transfer data. - sptd_sb.sptd.TimeOutValue=108000; //SCSI timeout value (max 108000 sec = time 30 min). - sptd_sb.sptd.DataBuffer=(PVOID)data_buf; - sptd_sb.sptd.SenseInfoOffset=sizeof(SCSI_PASS_THROUGH_DIRECT); - - //CDB with values for set cd speed command. - //The values were taken from MMC1 draft paper. - sptd_sb.sptd.Cdb[0]=0xBB; //Code for set cd speed command. - sptd_sb.sptd.Cdb[1]=0; - sptd_sb.sptd.Cdb[2]=(unsigned char)(in_read_speed>>8); - sptd_sb.sptd.Cdb[3]=(unsigned char)in_read_speed; - sptd_sb.sptd.Cdb[4]=(unsigned char)(in_write_speed>>8); - sptd_sb.sptd.Cdb[5]=(unsigned char)in_write_speed; - sptd_sb.sptd.Cdb[6]=0; - sptd_sb.sptd.Cdb[7]=0; - sptd_sb.sptd.Cdb[8]=0; - sptd_sb.sptd.Cdb[9]=0; - sptd_sb.sptd.Cdb[10]=0; - sptd_sb.sptd.Cdb[11]=0; - sptd_sb.sptd.Cdb[12]=0; - sptd_sb.sptd.Cdb[13]=0; - sptd_sb.sptd.Cdb[14]=0; - sptd_sb.sptd.Cdb[15]=0; - - ZeroMemory(sptd_sb.SenseBuf, MAX_SENSE_LEN); - - //Send the command to drive - return DeviceIoControl(hVolume, - IOCTL_SCSI_PASS_THROUGH_DIRECT, - (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), - (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), - &dwBytesReturned, - NULL); -} - -/* - 1. Set up the sptd values. - 2. Set up the CDB for MMC1 read TOC/PMA/ATIP command. - 3. Send the request to the drive. -*/ -BOOL read_TOC_PMA_ATIP(HANDLE hVolume, - unsigned char in_format, - unsigned char in_trk_sess_no, - unsigned short int in_data_trans_len) -{ - DWORD dwBytesReturned; - - sptd_sb.sptd.Length=sizeof(SCSI_PASS_THROUGH_DIRECT); - sptd_sb.sptd.PathId=0; //SCSI card ID will be filled in automatically. - sptd_sb.sptd.TargetId=0; //SCSI target ID will also be filled in. - sptd_sb.sptd.Lun=0; //SCSI lun ID will also be filled in. - sptd_sb.sptd.CdbLength=10; //CDB size. - sptd_sb.sptd.SenseInfoLength=MAX_SENSE_LEN; //Maximum length of sense data to retrieve. - sptd_sb.sptd.DataIn=SCSI_IOCTL_DATA_IN; //There will be data from drive. - sptd_sb.sptd.DataTransferLength=in_data_trans_len; //Size of input data from drive. - sptd_sb.sptd.TimeOutValue=108000; //SCSI timeout value (max 108000 sec = time 30 min). - sptd_sb.sptd.DataBuffer=(PVOID)data_buf; - sptd_sb.sptd.SenseInfoOffset=sizeof(SCSI_PASS_THROUGH_DIRECT); - - //CDB with values for READ TOC/PMA/ATIP CDB10 command. - //The values were taken from MMC draft paper. - sptd_sb.sptd.Cdb[0]=0x43; //Code for READ TOC/PMA/ATIP CDB10 command. - sptd_sb.sptd.Cdb[1]=0; - sptd_sb.sptd.Cdb[2]=in_format; //Format code. - sptd_sb.sptd.Cdb[3]=0; - sptd_sb.sptd.Cdb[4]=0; - sptd_sb.sptd.Cdb[5]=0; - sptd_sb.sptd.Cdb[6]=in_trk_sess_no; - sptd_sb.sptd.Cdb[7]=(unsigned char)(in_data_trans_len >> 8); //MSB of max length of bytes to receive. - sptd_sb.sptd.Cdb[8]=(unsigned char)in_data_trans_len; //LSB of max length of bytes to receive. - sptd_sb.sptd.Cdb[9]=0; - sptd_sb.sptd.Cdb[10]=0; - sptd_sb.sptd.Cdb[11]=0; - sptd_sb.sptd.Cdb[12]=0; - sptd_sb.sptd.Cdb[13]=0; - sptd_sb.sptd.Cdb[14]=0; - sptd_sb.sptd.Cdb[15]=0; - - ZeroMemory(data_buf, in_data_trans_len); - ZeroMemory(sptd_sb.SenseBuf, MAX_SENSE_LEN); - - //Send the command to drive. - return DeviceIoControl(hVolume, - IOCTL_SCSI_PASS_THROUGH_DIRECT, - (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), - (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), - &dwBytesReturned, - NULL); -} - -/* - 1. Set up the sptd values. - 2. Set up the CDB for MMC1 read CD (0xBE, CDB12) command. - 3. Send the request to the drive. -*/ -BOOL read_cd_2048(HANDLE hVolume, - long int MMC_LBA_sector, - unsigned long int n_sectors, - unsigned char subch_sel_bits) -{ - DWORD dwBytesReturned; - long int MMC_LBA_sector2; - unsigned long int n_sectors2; - - sptd_sb.sptd.Length=sizeof(SCSI_PASS_THROUGH_DIRECT); - sptd_sb.sptd.PathId=0; //SCSI card ID will be filled in automatically. - sptd_sb.sptd.TargetId=0; //SCSI target ID will also be filled in. - sptd_sb.sptd.Lun=0; //SCSI lun ID will also be filled in. - sptd_sb.sptd.CdbLength=12; //CDB size. - sptd_sb.sptd.SenseInfoLength=MAX_SENSE_LEN; //Maximum length of sense data to retrieve. - sptd_sb.sptd.DataIn=SCSI_IOCTL_DATA_IN; //There will be data coming from the drive. - sptd_sb.sptd.DataTransferLength=2048*n_sectors; //Size of read data. - sptd_sb.sptd.TimeOutValue=108000; //SCSI timeout value (max 108000 sec = time 30 min). - sptd_sb.sptd.DataBuffer=(PVOID)data_buf; - sptd_sb.sptd.SenseInfoOffset=sizeof(SCSI_PASS_THROUGH_DIRECT); - - //CDB with values for Read CD command. The values were taken from MMC1 draft paper. - sptd_sb.sptd.Cdb[0]=0xBE; //Code for Read CD command. - sptd_sb.sptd.Cdb[1]=0; - - //Fill in starting MMC sector (CDB[2] to CDB[5]).. - sptd_sb.sptd.Cdb[5]=(unsigned char)MMC_LBA_sector; //Least sig byte of LBA sector no. to read from CD. - MMC_LBA_sector2=MMC_LBA_sector>>8; - sptd_sb.sptd.Cdb[4]=(unsigned char)MMC_LBA_sector2; //2nd byte. - MMC_LBA_sector2=MMC_LBA_sector2>>8; - sptd_sb.sptd.Cdb[3]=(unsigned char)MMC_LBA_sector2; //3rd byte. - MMC_LBA_sector2=MMC_LBA_sector2>>8; - sptd_sb.sptd.Cdb[2]=(unsigned char)MMC_LBA_sector2; //Most significant byte. - - //Fill in no. of sectors to read (CDB[6] to CDB[8]).. - sptd_sb.sptd.Cdb[8]=(unsigned char)n_sectors; //No. of sectors to read from CD byte 0 (LSB). - n_sectors2=n_sectors>>8; - sptd_sb.sptd.Cdb[7]=(unsigned char)n_sectors2; //No. of sectors to read from CD byte 1. - n_sectors2=n_sectors2>>8; - sptd_sb.sptd.Cdb[6]=(unsigned char)n_sectors2; //No. of sectors to read from CD byte 2 (MSB). - - sptd_sb.sptd.Cdb[9]=0x10; //Read user data only, 2048 bytes per sector from CDROM. - sptd_sb.sptd.Cdb[10]=subch_sel_bits; //Sub-channel selection bits. - sptd_sb.sptd.Cdb[11]=0; - sptd_sb.sptd.Cdb[12]=0; - sptd_sb.sptd.Cdb[13]=0; - sptd_sb.sptd.Cdb[14]=0; - sptd_sb.sptd.Cdb[15]=0; - - ZeroMemory(data_buf, 2048*n_sectors); - ZeroMemory(sptd_sb.SenseBuf, MAX_SENSE_LEN); - - //Send the command to drive. - return DeviceIoControl(hVolume, - IOCTL_SCSI_PASS_THROUGH_DIRECT, - (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), - (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), - &dwBytesReturned, - NULL); -} - -/* -Calculating data rate of digital stereo (2 channels) audio at 44.1 KHz with 16 BITs per channel. ------------------------------------------------------------------------------------------------- -Number of bytes taken up by 1 sample of audio: -16 BIT = 1 word = 2 bytes, but there are 2 channels, so 1 sample takes up -2*2=4 bytes. - -Data rate in kilobytes/sec will be: - s=Number of samples per second - b=Number of bytes per sample - - s*b - ---- = data rate kb/s - 1000 -So data rate of the digital audio is: - 44100*4 - ------- = 176.4 kb/s - 1000 -This data rate is used by CDROM/CD writers as 1X speed. This will of course have to be rounded to -a whole number: 176 kb/s, making prog. easier. Note, kb is in units of 1000. -*/ -unsigned short int kbytes_2_x_speed(unsigned short int speed_kbytes) -{ - return RoundDouble(speed_kbytes/176.4, 0); -} -unsigned short int x_2_kbytes_speed(unsigned short int x_speed) -{ - return RoundDouble(x_speed*176.4, 0); -} - -BOOL verified_set_cd_speed(HANDLE hVolume, - unsigned short int in_read_speed, - unsigned short int in_write_speed) -{ - BOOL success; - - printf("Sending MMC1 CD speed command "); - if(in_read_speed==0xFFFF) - { - printf("(read: max speed, "); - } - else - { - printf("(read: %ukbytes (%ux)", in_read_speed, kbytes_2_x_speed(in_read_speed)); - } - if(in_write_speed==0xFFFF) - { - printf("write: max speed).."); - } - else - { - printf("write: %ukbytes (%ux))..", in_write_speed, kbytes_2_x_speed(in_write_speed)); - } - - //Sends MMC1 set CD speed command to drive. - success=set_cd_speed(hVolume, in_read_speed, in_write_speed); - if(success) - { - printf("done.\n"); - if(sptd_sb.sptd.ScsiStatus==STATUS_GOOD) - { - //Do nothing. - } - else - { - success=FALSE; - if(sptd_sb.sptd.ScsiStatus==STATUS_CHKCOND) - { - disp_sense(); - } - else - { - printf("Command sent but returned with an unhandled status code: %02X\n", sptd_sb.sptd.ScsiStatus); - } - } - } - else - { - printf("failed.\n"); - printf("DeviceIOControl returned with failed status.\n"); - } - - return success; -} - -/* Sends Read TOC/PMA/ATIP command to read TOC, check & display errors and return the success state. */ -BOOL verified_read_TOC(HANDLE hVolume, - unsigned long int data_buffer_size) -{ - BOOL success; - unsigned short int alloc_len=0; - - printf("Sending read TOC command.."); - //Sends MMC1 READ TOC/PMA/ATIP command to drive to get 4 byte header. - success=read_TOC_PMA_ATIP(hVolume, 0, 0, 4); - if(success) - { - if(sptd_sb.sptd.ScsiStatus==STATUS_GOOD) - { - alloc_len=data_buf[0] << 8; - alloc_len=alloc_len | data_buf[1]; - } - else - { - success=FALSE; - printf("done.\n"); - if(sptd_sb.sptd.ScsiStatus==STATUS_CHKCOND) - { - disp_sense(); - } - else - { - printf("Command sent but returned with an unhandled status code: %02X\n", sptd_sb.sptd.ScsiStatus); - } - } - } - else - { - printf("failed.\n"); - printf("Could not return 4 byte Read TOC header.\n"); - } - - if(success && (alloc_len>0)) - { - //Limit alloc len to maximum allowed by size of data transfer buffer length. - if((alloc_len+2)>data_buffer_size) - { - alloc_len=data_buffer_size-2; - } - - //Sends MMC1 READ TOC/PMA/ATIP command to drive to get full data. - success=read_TOC_PMA_ATIP(hVolume, 0, 0, alloc_len+2); - if(success) - { - printf("done.\n"); - if(sptd_sb.sptd.ScsiStatus==STATUS_GOOD) - { - alloc_len=data_buf[0] << 8; - alloc_len=alloc_len | data_buf[1]; - } - else - { - success=FALSE; - if(sptd_sb.sptd.ScsiStatus==STATUS_CHKCOND) - { - disp_sense(); - } - else - { - printf("Command sent but returned with an unhandled status code: %02X\n", sptd_sb.sptd.ScsiStatus); - } - } - } - else - { - printf("failed.\n"); - printf("Could only return 4 byte Read TOC header.\n"); - } - } - - return success; -} - -/* Sends Test Unit Ready command 3 times, check for errors & display error info. */ -BOOL verified_test_unit_ready3(HANDLE hVolume) -{ - unsigned char i=3; - BOOL success; - - /* - Before sending the required command, here we clear any pending sense info from the drive - which may interfere by sending Test Unit Ready command at least 3 times if neccessary. - ----------------------------------------------------------------------------------------*/ - do - { - printf("Sending SPC1 Test Unit CDB6 command.."); - //Sends SPC1 Test Unit Ready command to drive - success=test_unit_ready(hVolume); - if(success) - { - printf("done.\n"); - if(sptd_sb.sptd.ScsiStatus==STATUS_GOOD) - { - printf("Returned good status.\n"); - i=1; - } - else - { - if(sptd_sb.sptd.ScsiStatus==STATUS_CHKCOND) - { - disp_sense(); - } - else - { - printf("Command sent but returned with an unhandled status code: %02X\n", sptd_sb.sptd.ScsiStatus); - } - - success=FALSE; - } - } - else - { - printf("failed.\n"); - printf("DeviceIOControl returned with failed status.\n"); - } - i--; - }while(i>0); - - return success; -} - -//Find lead-out from read TOC data. -BOOL find_leadout_from_TOC(unsigned char *data_buf, - unsigned char &out_n_tracks, - unsigned long int &out_n_sectors) -{ - unsigned long int i; - unsigned long int sector; - unsigned short int alloc_len; - unsigned short int TOC_response_data_len; - BOOL found_leadout; - - alloc_len=data_buf[0] << 8; - alloc_len=alloc_len | data_buf[1]; - TOC_response_data_len=alloc_len+2; - found_leadout=FALSE; - out_n_tracks=0; - //Iterate thru TOC entries to find track 0xAA (leadout track).. - for(i=4;i0) - { - //Total sectors before lead-out. - out_n_sectors=sector; - } - else - { - //Error, this should never happen. - out_n_sectors=0; - } - - out_n_tracks--; //Don't include this track. - - found_leadout=TRUE; - } - - out_n_tracks++; - } - } - } - - return found_leadout; -} - -/* -Main loop of reading the CD and writing to image file. -Various error checking are also done here. -*/ -BOOL read_cd_to_image(char drive_letter, char *file_pathname, unsigned short int x_speed, unsigned long int data_buffer_size) -{ - HANDLE hVolume; - BOOL success; - unsigned char n_tracks; //Total tracks. - unsigned long int n_sectors; //Total sectors on CD. - FILE *file_ptr; - unsigned long int LBA_i; //For counting "from" LBA (starts from 0). - unsigned long int LBA_i2; //For calculating "to" LBA. - unsigned long int n_sectors_to_read; //No. of sectors to read per read command. - unsigned short int speed_kbytes; //Write speed in kbytes. - - hVolume = open_volume(drive_letter); - if (hVolume != INVALID_HANDLE_VALUE) - { - printf("\n"); - success=verified_test_unit_ready3(hVolume); - printf("\n"); - if(success) - { - //Get TOC from CD. - success=verified_read_TOC(hVolume, data_buffer_size); - if(success) - { - if(find_leadout_from_TOC(data_buf, n_tracks, n_sectors)) - { - printf("Total user tracks : %u\n", n_tracks); - printf("Total sectors : %u\n", n_sectors); - - //Do we need to set CD speed? - if(x_speed!=0) - { - if(x_speed==0xFFFF) - { - speed_kbytes=0xFFFF; //Use maximum write speed. - } - else - { - //Convert x speed to kbytes speed. - speed_kbytes=x_2_kbytes_speed(x_speed); - } - - //Attempt to set the cd read speed to specified and write speed to max. - success=verified_set_cd_speed(hVolume, speed_kbytes, 0xFFFF); - } - else - { - //No need to set CD speed. - success=TRUE; - } - if(success) - { - file_ptr=fopen(file_pathname, "wb"); - if(file_ptr!=NULL) - { - n_sectors_to_read=data_buffer_size / 2048; //Block size: E.g.: 65536 / 2048 = 32. - LBA_i=0; //Starting LBA address. - while(LBA_i(n_sectors-LBA_i)) - { - //Alter to the remaining sectors. - n_sectors_to_read=n_sectors-LBA_i; - } - - LBA_i2=LBA_i+n_sectors_to_read-1; - printf("Reading sector %u to %u (total: %u, progress: %.1f%%)\n", LBA_i, LBA_i2, n_sectors, (double)LBA_i2/n_sectors*100); - if(read_cd_2048(hVolume, LBA_i, n_sectors_to_read, 0)) - { - if(sptd_sb.sptd.ScsiStatus==STATUS_GOOD) - { - fwrite(data_buf, 2048*n_sectors_to_read, 1, file_ptr); - if(ferror(file_ptr)) - { - printf("Write file error!\n"); - printf("Aborting process.\n"); - success=FALSE; - break; //Stop while loop. - } - } - else - { - if(sptd_sb.sptd.ScsiStatus==STATUS_CHKCOND) - { - disp_sense(); - } - else - { - printf("Command sent but returned with an unhandled status code: %02X\n", sptd_sb.sptd.ScsiStatus); - } - - printf("Aborting process.\n"); - success=FALSE; - break; //Stop while loop. - } - } - - LBA_i=LBA_i+n_sectors_to_read; - } - - fclose(file_ptr); - } - else - { - printf("Could not create file!\n"); - printf("Aborting process.\n"); - success=FALSE; - } - } - else - { - printf("Could not set read speed!\n"); - printf("Aborting process.\n"); - } - } - else - { - printf("Could not find lead-out entry in TOC to determine total sectors on CD!\n"); - printf("Aborting process.\n"); - success=FALSE; - } - } - else - { - printf("Could not read TOC!\n"); - printf("Aborting process.\n"); - } - } - else - { - printf("Drive is not ready!\n"); - printf("Aborting process.\n"); - } - - CloseHandle(hVolume); //Win32 function. - } - else - { - return FALSE; - } - - return success; -} - -void usage() -{ - printf("CDToImg v1.01. 22 Oct 2006.\n"); - printf("Usage: cdtoimg [x read speed]\n"); - printf("x speed is one of the following:\n"); - printf(" - Enter CD x speed value.\n"); - printf(" - Ommit or enter 0 to use currently set speed.\n"); - printf(" - Enter m for max speed.\n"); - return ; //Exit program here. -} - -void main(int argc, char *argv[]) -{ - unsigned short int x_speed; - - if((argc == 3) || (argc == 4)) - { - //65536 data transfer buffer. - data_buf=(unsigned char *)malloc(65536); - - if(argc == 3) - { - x_speed=0; //Use currently set write speed. - } - else - { - if(x_speed=argv[3][0]=='m') - { - x_speed=0xFFFF; //Use maximum write speed. - } - else - { - x_speed=atoi(argv[3]); //Use specified write speed. - } - } - if(read_cd_to_image(argv[1][0], argv[2], x_speed, 65536)) - { - printf("Process finished."); - } - else - { - printf("Could not create image from drive %c.", argv[1][0]); - } - - free(data_buf); - } - else - { - usage(); - return ; //Exit program here. - } -} \ No newline at end of file +/* +CDToImg v1.01. +22 Oct 2006. +Written by Truman. + +Language and type: MS Visual Studio .NET 2002, Visual C++ v7, mixed C and C++, +Application type : Win32 console. + +A program that reads an entire CD-ROM (mode 1 or mode 2 form 1) 2048 bytes per +sector and writes to a file - this would be an .ISO file. The CD must be CD-ROM +mode 1 or mode 2 and non-multisession. Note, it does not check if the CD is +valid. TAO writing mode creates link blocks and this program does not detect +them so if encountered will be considered as a normal sector or unreadable. +Unreadable sectors are not supported and will terminate the process. Only up to +80 minutes reading is supported for the moment. Note that some drives will +ignore certain read speeds, e.g. my Plextor 755A can only be set to a minimum +of 4x read speed. On some drives, reading the last few sectors or ejecting the +disc when reading in 2048 byte/sector mode results in a hang (e.g.: LG CDROM +drive: HL-DT-ST CDROM GCR-8485B 1.05). + +As always I do not take any responsibilities if this tool destroys your drive or +even anything else. + +This code uses: +- Win32 IOCTL function with SCSI_PASS_THROUGH_DIRECT. +- The SCSI codes used in this source were taken from the draft documents MMC1, + SPC1 and SAM1. +- MMC1 Read CD command (0xBE, CDB 12) to read sectors (2048 user bytes mode). +- Determine errors, retrieve and decode a few sense data. + +Normally you need the ntddscsi.h file from Microsoft DDK CD, but I shouldn't +distribute it, so instead I have written my own my_ntddscsi.h. + +If you don't have windows.h some of the define constants are listed as comments. + +This is a Win32 console program and only runs in a DOS prompt under Windows +NT4/2K/XP/2003 with appropriate user rights, i.e. you need to log in as +administrator. + +Read readme.txt for more info. +*/ + +#include +#include +#include +#include "my_ntddscsi.h" +#include "sam.h" +#include "FloatUtils.h" + +//Global variables.. +T_SPDT_SBUF sptd_sb; //Includes sense buffer +unsigned char *data_buf; //Buffer for holding transfer data from or to drive. + +/* + 1. Check the drive type to see if it's identified as a CDROM drive + + 2. Uses Win32 CreateFile function to get a handle to a drive + that is specified by cDriveLetter. + + If you don't have windows.h, some of the define constants are + listed as comments. +*/ +HANDLE open_volume(char drive_letter) +{ + HANDLE hVolume; + UINT uDriveType; + char szVolumeName[8]; + char szRootName[5]; + + //Make drive_letter as a null terminated string in the form of e.g.: d:\. + szRootName[0]=drive_letter; + szRootName[1]=':'; + szRootName[2]='\\'; + szRootName[3]='\0'; + + uDriveType = GetDriveType(szRootName); + + //#define GENERIC_READ 0x80000000L + //#define GENERIC_WRITE 0x40000000L + switch(uDriveType) + { + case DRIVE_CDROM: + { + printf("Drive type is recognised as CDROM/DVD.\n"); + break; + } + default: + { + printf("Drive type is not CDROM/DVD, aborting.\n"); + return INVALID_HANDLE_VALUE; //#define INVALID_HANDLE_VALUE (long int *)-1 + } + } + + //Make drive_letter as a null terminated string in the form of e.g.: \\.\d:. + szVolumeName[0]='\\'; + szVolumeName[1]='\\'; + szVolumeName[2]='.'; + szVolumeName[3]='\\'; + szVolumeName[4]=drive_letter; + szVolumeName[5]=':'; + szVolumeName[6]='\0'; + + //#define FILE_SHARE_READ 0x00000001 + //#define FILE_SHARE_WRITE 0x00000002 + //#define OPEN_EXISTING 3 + //#define FILE_ATTRIBUTE_NORMAL 0x00000080 + //This will only work for CD/DVD device on W2K and higher. + hVolume = CreateFile(szVolumeName, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if(hVolume == INVALID_HANDLE_VALUE) + { + //Try again for NT4.. + hVolume = CreateFile(szVolumeName, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if(hVolume == INVALID_HANDLE_VALUE) + { + printf("Could not create handle for CD/DVD device.\n"); + } + } + + return hVolume; +} + +/* Displays sense error information. */ +void disp_sense() +{ + unsigned char key; + unsigned char ASC; + unsigned char ASCQ; + + key=sptd_sb.SenseBuf[2] & 0x0F; //Sense key is only the lower 4 bits + ASC=sptd_sb.SenseBuf[12]; + ASCQ=sptd_sb.SenseBuf[13]; + + printf("Sense data, key:ASC:ASCQ: %02X:%02X:%02X", key, ASC, ASCQ); + + //Decode sense key:ASC:ASCQ. + //It's a very short list - I'm just trying to show you how to decode into text. + //You really need to look into MMC document and change this into an exhaustive list from + //the sense error table that is found in there. + if(key==SEN_KEY_NO_SEN) + { + if(ASC==0x00) + { + if(ASCQ==0x00) + { + printf(" - No additional sense info."); //No errors + } + } + } + else + if(key==SEN_KEY_NOT_READY) + { + if(ASC==0x3A) + { + if(ASCQ==0x00) + { + printf(" - Medium not present."); + } + else + if(ASCQ==0x01) + { + printf(" - Medium not present-tray closed."); + } + else + if(ASCQ==0x02) + { + printf(" - Medium not present-tray open."); + } + } + } + + printf("\n"); +} + +/* + 1. Set up the sptd values. + 2. Set up the CDB for SPC1 test unit ready command. + 3. Send the request to the drive. +*/ +BOOL test_unit_ready(HANDLE hVolume) +{ + DWORD dwBytesReturned; + + sptd_sb.sptd.Length=sizeof(SCSI_PASS_THROUGH_DIRECT); + sptd_sb.sptd.PathId=0; //SCSI card ID will be filled in automatically. + sptd_sb.sptd.TargetId=0; //SCSI target ID will also be filled in. + sptd_sb.sptd.Lun=0; //SCSI lun ID will also be filled in. + sptd_sb.sptd.CdbLength=6; //CDB size. + sptd_sb.sptd.SenseInfoLength=MAX_SENSE_LEN; //Maximum length of sense data to retrieve. + sptd_sb.sptd.DataIn=SCSI_IOCTL_DATA_UNSPECIFIED; //There will be no buffer data to/from drive. + sptd_sb.sptd.DataTransferLength=0; //Size of buffer transfer data. + sptd_sb.sptd.TimeOutValue=108000; //SCSI timeout value (max 108000 sec = time 30 min). + sptd_sb.sptd.DataBuffer=(PVOID)data_buf; + sptd_sb.sptd.SenseInfoOffset=sizeof(SCSI_PASS_THROUGH_DIRECT); + + //CDB with values for Test Unit Ready CDB6 command. + //The values were taken from SPC1 draft paper. + sptd_sb.sptd.Cdb[0]=0x00; //Code for Test Unit Ready CDB6 command. + sptd_sb.sptd.Cdb[1]=0; + sptd_sb.sptd.Cdb[2]=0; + sptd_sb.sptd.Cdb[3]=0; + sptd_sb.sptd.Cdb[4]=0; + sptd_sb.sptd.Cdb[5]=0; + sptd_sb.sptd.Cdb[6]=0; + sptd_sb.sptd.Cdb[7]=0; + sptd_sb.sptd.Cdb[8]=0; + sptd_sb.sptd.Cdb[9]=0; + sptd_sb.sptd.Cdb[10]=0; + sptd_sb.sptd.Cdb[11]=0; + sptd_sb.sptd.Cdb[12]=0; + sptd_sb.sptd.Cdb[13]=0; + sptd_sb.sptd.Cdb[14]=0; + sptd_sb.sptd.Cdb[15]=0; + + ZeroMemory(sptd_sb.SenseBuf, MAX_SENSE_LEN); + + //Send the command to drive. + return DeviceIoControl(hVolume, + IOCTL_SCSI_PASS_THROUGH_DIRECT, + (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), + (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), + &dwBytesReturned, + NULL); +} + +/* + 1. Set up the sptd values. + 2. Set up the CDB for MMC1 set CD speed command. + 3. Send the request to the drive. +*/ +BOOL set_cd_speed(HANDLE hVolume, + unsigned short int in_read_speed, + unsigned short int in_write_speed) +{ + DWORD dwBytesReturned; + + sptd_sb.sptd.Length=sizeof(SCSI_PASS_THROUGH_DIRECT); + sptd_sb.sptd.PathId=0; //SCSI card ID will be filled in automatically. + sptd_sb.sptd.TargetId=0; //SCSI target ID will also be filled in. + sptd_sb.sptd.Lun=0; //SCSI lun ID will also be filled in. + sptd_sb.sptd.CdbLength=12; //CDB size + sptd_sb.sptd.SenseInfoLength=MAX_SENSE_LEN; //Return sense buffer length. + sptd_sb.sptd.DataIn=SCSI_IOCTL_DATA_UNSPECIFIED; //There will be no buffer data to/from drive. + sptd_sb.sptd.DataTransferLength=0; //Size of buffer transfer data. + sptd_sb.sptd.TimeOutValue=108000; //SCSI timeout value (max 108000 sec = time 30 min). + sptd_sb.sptd.DataBuffer=(PVOID)data_buf; + sptd_sb.sptd.SenseInfoOffset=sizeof(SCSI_PASS_THROUGH_DIRECT); + + //CDB with values for set cd speed command. + //The values were taken from MMC1 draft paper. + sptd_sb.sptd.Cdb[0]=0xBB; //Code for set cd speed command. + sptd_sb.sptd.Cdb[1]=0; + sptd_sb.sptd.Cdb[2]=(unsigned char)(in_read_speed>>8); + sptd_sb.sptd.Cdb[3]=(unsigned char)in_read_speed; + sptd_sb.sptd.Cdb[4]=(unsigned char)(in_write_speed>>8); + sptd_sb.sptd.Cdb[5]=(unsigned char)in_write_speed; + sptd_sb.sptd.Cdb[6]=0; + sptd_sb.sptd.Cdb[7]=0; + sptd_sb.sptd.Cdb[8]=0; + sptd_sb.sptd.Cdb[9]=0; + sptd_sb.sptd.Cdb[10]=0; + sptd_sb.sptd.Cdb[11]=0; + sptd_sb.sptd.Cdb[12]=0; + sptd_sb.sptd.Cdb[13]=0; + sptd_sb.sptd.Cdb[14]=0; + sptd_sb.sptd.Cdb[15]=0; + + ZeroMemory(sptd_sb.SenseBuf, MAX_SENSE_LEN); + + //Send the command to drive + return DeviceIoControl(hVolume, + IOCTL_SCSI_PASS_THROUGH_DIRECT, + (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), + (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), + &dwBytesReturned, + NULL); +} + +/* + 1. Set up the sptd values. + 2. Set up the CDB for MMC1 read TOC/PMA/ATIP command. + 3. Send the request to the drive. +*/ +BOOL read_TOC_PMA_ATIP(HANDLE hVolume, + unsigned char in_format, + unsigned char in_trk_sess_no, + unsigned short int in_data_trans_len) +{ + DWORD dwBytesReturned; + + sptd_sb.sptd.Length=sizeof(SCSI_PASS_THROUGH_DIRECT); + sptd_sb.sptd.PathId=0; //SCSI card ID will be filled in automatically. + sptd_sb.sptd.TargetId=0; //SCSI target ID will also be filled in. + sptd_sb.sptd.Lun=0; //SCSI lun ID will also be filled in. + sptd_sb.sptd.CdbLength=10; //CDB size. + sptd_sb.sptd.SenseInfoLength=MAX_SENSE_LEN; //Maximum length of sense data to retrieve. + sptd_sb.sptd.DataIn=SCSI_IOCTL_DATA_IN; //There will be data from drive. + sptd_sb.sptd.DataTransferLength=in_data_trans_len; //Size of input data from drive. + sptd_sb.sptd.TimeOutValue=108000; //SCSI timeout value (max 108000 sec = time 30 min). + sptd_sb.sptd.DataBuffer=(PVOID)data_buf; + sptd_sb.sptd.SenseInfoOffset=sizeof(SCSI_PASS_THROUGH_DIRECT); + + //CDB with values for READ TOC/PMA/ATIP CDB10 command. + //The values were taken from MMC draft paper. + sptd_sb.sptd.Cdb[0]=0x43; //Code for READ TOC/PMA/ATIP CDB10 command. + sptd_sb.sptd.Cdb[1]=0; + sptd_sb.sptd.Cdb[2]=in_format; //Format code. + sptd_sb.sptd.Cdb[3]=0; + sptd_sb.sptd.Cdb[4]=0; + sptd_sb.sptd.Cdb[5]=0; + sptd_sb.sptd.Cdb[6]=in_trk_sess_no; + sptd_sb.sptd.Cdb[7]=(unsigned char)(in_data_trans_len >> 8); //MSB of max length of bytes to receive. + sptd_sb.sptd.Cdb[8]=(unsigned char)in_data_trans_len; //LSB of max length of bytes to receive. + sptd_sb.sptd.Cdb[9]=0; + sptd_sb.sptd.Cdb[10]=0; + sptd_sb.sptd.Cdb[11]=0; + sptd_sb.sptd.Cdb[12]=0; + sptd_sb.sptd.Cdb[13]=0; + sptd_sb.sptd.Cdb[14]=0; + sptd_sb.sptd.Cdb[15]=0; + + ZeroMemory(data_buf, in_data_trans_len); + ZeroMemory(sptd_sb.SenseBuf, MAX_SENSE_LEN); + + //Send the command to drive. + return DeviceIoControl(hVolume, + IOCTL_SCSI_PASS_THROUGH_DIRECT, + (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), + (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), + &dwBytesReturned, + NULL); +} + +/* + 1. Set up the sptd values. + 2. Set up the CDB for MMC1 read CD (0xBE, CDB12) command. + 3. Send the request to the drive. +*/ +BOOL read_cd_2048(HANDLE hVolume, + long int MMC_LBA_sector, + unsigned long int n_sectors, + unsigned char subch_sel_bits) +{ + DWORD dwBytesReturned; + long int MMC_LBA_sector2; + unsigned long int n_sectors2; + + sptd_sb.sptd.Length=sizeof(SCSI_PASS_THROUGH_DIRECT); + sptd_sb.sptd.PathId=0; //SCSI card ID will be filled in automatically. + sptd_sb.sptd.TargetId=0; //SCSI target ID will also be filled in. + sptd_sb.sptd.Lun=0; //SCSI lun ID will also be filled in. + sptd_sb.sptd.CdbLength=12; //CDB size. + sptd_sb.sptd.SenseInfoLength=MAX_SENSE_LEN; //Maximum length of sense data to retrieve. + sptd_sb.sptd.DataIn=SCSI_IOCTL_DATA_IN; //There will be data coming from the drive. + sptd_sb.sptd.DataTransferLength=2048*n_sectors; //Size of read data. + sptd_sb.sptd.TimeOutValue=108000; //SCSI timeout value (max 108000 sec = time 30 min). + sptd_sb.sptd.DataBuffer=(PVOID)data_buf; + sptd_sb.sptd.SenseInfoOffset=sizeof(SCSI_PASS_THROUGH_DIRECT); + + //CDB with values for Read CD command. The values were taken from MMC1 draft paper. + sptd_sb.sptd.Cdb[0]=0xBE; //Code for Read CD command. + sptd_sb.sptd.Cdb[1]=0; + + //Fill in starting MMC sector (CDB[2] to CDB[5]).. + sptd_sb.sptd.Cdb[5]=(unsigned char)MMC_LBA_sector; //Least sig byte of LBA sector no. to read from CD. + MMC_LBA_sector2=MMC_LBA_sector>>8; + sptd_sb.sptd.Cdb[4]=(unsigned char)MMC_LBA_sector2; //2nd byte. + MMC_LBA_sector2=MMC_LBA_sector2>>8; + sptd_sb.sptd.Cdb[3]=(unsigned char)MMC_LBA_sector2; //3rd byte. + MMC_LBA_sector2=MMC_LBA_sector2>>8; + sptd_sb.sptd.Cdb[2]=(unsigned char)MMC_LBA_sector2; //Most significant byte. + + //Fill in no. of sectors to read (CDB[6] to CDB[8]).. + sptd_sb.sptd.Cdb[8]=(unsigned char)n_sectors; //No. of sectors to read from CD byte 0 (LSB). + n_sectors2=n_sectors>>8; + sptd_sb.sptd.Cdb[7]=(unsigned char)n_sectors2; //No. of sectors to read from CD byte 1. + n_sectors2=n_sectors2>>8; + sptd_sb.sptd.Cdb[6]=(unsigned char)n_sectors2; //No. of sectors to read from CD byte 2 (MSB). + + sptd_sb.sptd.Cdb[9]=0x10; //Read user data only, 2048 bytes per sector from CDROM. + sptd_sb.sptd.Cdb[10]=subch_sel_bits; //Sub-channel selection bits. + sptd_sb.sptd.Cdb[11]=0; + sptd_sb.sptd.Cdb[12]=0; + sptd_sb.sptd.Cdb[13]=0; + sptd_sb.sptd.Cdb[14]=0; + sptd_sb.sptd.Cdb[15]=0; + + ZeroMemory(data_buf, 2048*n_sectors); + ZeroMemory(sptd_sb.SenseBuf, MAX_SENSE_LEN); + + //Send the command to drive. + return DeviceIoControl(hVolume, + IOCTL_SCSI_PASS_THROUGH_DIRECT, + (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), + (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), + &dwBytesReturned, + NULL); +} + +/* +Calculating data rate of digital stereo (2 channels) audio at 44.1 KHz with 16 BITs per channel. +------------------------------------------------------------------------------------------------ +Number of bytes taken up by 1 sample of audio: +16 BIT = 1 word = 2 bytes, but there are 2 channels, so 1 sample takes up +2*2=4 bytes. + +Data rate in kilobytes/sec will be: + s=Number of samples per second + b=Number of bytes per sample + + s*b + ---- = data rate kb/s + 1000 +So data rate of the digital audio is: + 44100*4 + ------- = 176.4 kb/s + 1000 +This data rate is used by CDROM/CD writers as 1X speed. This will of course have to be rounded to +a whole number: 176 kb/s, making prog. easier. Note, kb is in units of 1000. +*/ +unsigned short int kbytes_2_x_speed(unsigned short int speed_kbytes) +{ + return RoundDouble(speed_kbytes/176.4, 0); +} +unsigned short int x_2_kbytes_speed(unsigned short int x_speed) +{ + return RoundDouble(x_speed*176.4, 0); +} + +BOOL verified_set_cd_speed(HANDLE hVolume, + unsigned short int in_read_speed, + unsigned short int in_write_speed) +{ + BOOL success; + + printf("Sending MMC1 CD speed command "); + if(in_read_speed==0xFFFF) + { + printf("(read: max speed, "); + } + else + { + printf("(read: %ukbytes (%ux)", in_read_speed, kbytes_2_x_speed(in_read_speed)); + } + if(in_write_speed==0xFFFF) + { + printf("write: max speed).."); + } + else + { + printf("write: %ukbytes (%ux))..", in_write_speed, kbytes_2_x_speed(in_write_speed)); + } + + //Sends MMC1 set CD speed command to drive. + success=set_cd_speed(hVolume, in_read_speed, in_write_speed); + if(success) + { + printf("done.\n"); + if(sptd_sb.sptd.ScsiStatus==STATUS_GOOD) + { + //Do nothing. + } + else + { + success=FALSE; + if(sptd_sb.sptd.ScsiStatus==STATUS_CHKCOND) + { + disp_sense(); + } + else + { + printf("Command sent but returned with an unhandled status code: %02X\n", sptd_sb.sptd.ScsiStatus); + } + } + } + else + { + printf("failed.\n"); + printf("DeviceIOControl returned with failed status.\n"); + } + + return success; +} + +/* Sends Read TOC/PMA/ATIP command to read TOC, check & display errors and return the success state. */ +BOOL verified_read_TOC(HANDLE hVolume, + unsigned long int data_buffer_size) +{ + BOOL success; + unsigned short int alloc_len=0; + + printf("Sending read TOC command.."); + //Sends MMC1 READ TOC/PMA/ATIP command to drive to get 4 byte header. + success=read_TOC_PMA_ATIP(hVolume, 0, 0, 4); + if(success) + { + if(sptd_sb.sptd.ScsiStatus==STATUS_GOOD) + { + alloc_len=data_buf[0] << 8; + alloc_len=alloc_len | data_buf[1]; + } + else + { + success=FALSE; + printf("done.\n"); + if(sptd_sb.sptd.ScsiStatus==STATUS_CHKCOND) + { + disp_sense(); + } + else + { + printf("Command sent but returned with an unhandled status code: %02X\n", sptd_sb.sptd.ScsiStatus); + } + } + } + else + { + printf("failed.\n"); + printf("Could not return 4 byte Read TOC header.\n"); + } + + if(success && (alloc_len>0)) + { + //Limit alloc len to maximum allowed by size of data transfer buffer length. + if((alloc_len+2)>data_buffer_size) + { + alloc_len=data_buffer_size-2; + } + + //Sends MMC1 READ TOC/PMA/ATIP command to drive to get full data. + success=read_TOC_PMA_ATIP(hVolume, 0, 0, alloc_len+2); + if(success) + { + printf("done.\n"); + if(sptd_sb.sptd.ScsiStatus==STATUS_GOOD) + { + alloc_len=data_buf[0] << 8; + alloc_len=alloc_len | data_buf[1]; + } + else + { + success=FALSE; + if(sptd_sb.sptd.ScsiStatus==STATUS_CHKCOND) + { + disp_sense(); + } + else + { + printf("Command sent but returned with an unhandled status code: %02X\n", sptd_sb.sptd.ScsiStatus); + } + } + } + else + { + printf("failed.\n"); + printf("Could only return 4 byte Read TOC header.\n"); + } + } + + return success; +} + +/* Sends Test Unit Ready command 3 times, check for errors & display error info. */ +BOOL verified_test_unit_ready3(HANDLE hVolume) +{ + unsigned char i=3; + BOOL success; + + /* + Before sending the required command, here we clear any pending sense info from the drive + which may interfere by sending Test Unit Ready command at least 3 times if neccessary. + ----------------------------------------------------------------------------------------*/ + do + { + printf("Sending SPC1 Test Unit CDB6 command.."); + //Sends SPC1 Test Unit Ready command to drive + success=test_unit_ready(hVolume); + if(success) + { + printf("done.\n"); + if(sptd_sb.sptd.ScsiStatus==STATUS_GOOD) + { + printf("Returned good status.\n"); + i=1; + } + else + { + if(sptd_sb.sptd.ScsiStatus==STATUS_CHKCOND) + { + disp_sense(); + } + else + { + printf("Command sent but returned with an unhandled status code: %02X\n", sptd_sb.sptd.ScsiStatus); + } + + success=FALSE; + } + } + else + { + printf("failed.\n"); + printf("DeviceIOControl returned with failed status.\n"); + } + i--; + }while(i>0); + + return success; +} + +//Find lead-out from read TOC data. +BOOL find_leadout_from_TOC(unsigned char *data_buf, + unsigned char &out_n_tracks, + unsigned long int &out_n_sectors) +{ + unsigned long int i; + unsigned long int sector; + unsigned short int alloc_len; + unsigned short int TOC_response_data_len; + BOOL found_leadout; + + alloc_len=data_buf[0] << 8; + alloc_len=alloc_len | data_buf[1]; + TOC_response_data_len=alloc_len+2; + found_leadout=FALSE; + out_n_tracks=0; + //Iterate thru TOC entries to find track 0xAA (leadout track).. + for(i=4;i0) + { + //Total sectors before lead-out. + out_n_sectors=sector; + } + else + { + //Error, this should never happen. + out_n_sectors=0; + } + + out_n_tracks--; //Don't include this track. + + found_leadout=TRUE; + } + + out_n_tracks++; + } + } + } + + return found_leadout; +} + +/* +Main loop of reading the CD and writing to image file. +Various error checking are also done here. +*/ +BOOL read_cd_to_image(char drive_letter, char *file_pathname, unsigned short int x_speed, unsigned long int data_buffer_size) +{ + HANDLE hVolume; + BOOL success; + unsigned char n_tracks; //Total tracks. + unsigned long int n_sectors; //Total sectors on CD. + FILE *file_ptr; + unsigned long int LBA_i; //For counting "from" LBA (starts from 0). + unsigned long int LBA_i2; //For calculating "to" LBA. + unsigned long int n_sectors_to_read; //No. of sectors to read per read command. + unsigned short int speed_kbytes; //Write speed in kbytes. + + hVolume = open_volume(drive_letter); + if (hVolume != INVALID_HANDLE_VALUE) + { + printf("\n"); + success=verified_test_unit_ready3(hVolume); + printf("\n"); + if(success) + { + //Get TOC from CD. + success=verified_read_TOC(hVolume, data_buffer_size); + if(success) + { + if(find_leadout_from_TOC(data_buf, n_tracks, n_sectors)) + { + printf("Total user tracks : %u\n", n_tracks); + printf("Total sectors : %u\n", n_sectors); + + //Do we need to set CD speed? + if(x_speed!=0) + { + if(x_speed==0xFFFF) + { + speed_kbytes=0xFFFF; //Use maximum write speed. + } + else + { + //Convert x speed to kbytes speed. + speed_kbytes=x_2_kbytes_speed(x_speed); + } + + //Attempt to set the cd read speed to specified and write speed to max. + success=verified_set_cd_speed(hVolume, speed_kbytes, 0xFFFF); + } + else + { + //No need to set CD speed. + success=TRUE; + } + if(success) + { + file_ptr=fopen(file_pathname, "wb"); + if(file_ptr!=NULL) + { + n_sectors_to_read=data_buffer_size / 2048; //Block size: E.g.: 65536 / 2048 = 32. + LBA_i=0; //Starting LBA address. + while(LBA_i(n_sectors-LBA_i)) + { + //Alter to the remaining sectors. + n_sectors_to_read=n_sectors-LBA_i; + } + + LBA_i2=LBA_i+n_sectors_to_read-1; + printf("Reading sector %u to %u (total: %u, progress: %.1f%%)\n", LBA_i, LBA_i2, n_sectors, (double)LBA_i2/n_sectors*100); + if(read_cd_2048(hVolume, LBA_i, n_sectors_to_read, 0)) + { + if(sptd_sb.sptd.ScsiStatus==STATUS_GOOD) + { + fwrite(data_buf, 2048*n_sectors_to_read, 1, file_ptr); + if(ferror(file_ptr)) + { + printf("Write file error!\n"); + printf("Aborting process.\n"); + success=FALSE; + break; //Stop while loop. + } + } + else + { + if(sptd_sb.sptd.ScsiStatus==STATUS_CHKCOND) + { + disp_sense(); + } + else + { + printf("Command sent but returned with an unhandled status code: %02X\n", sptd_sb.sptd.ScsiStatus); + } + + printf("Aborting process.\n"); + success=FALSE; + break; //Stop while loop. + } + } + + LBA_i=LBA_i+n_sectors_to_read; + } + + fclose(file_ptr); + } + else + { + printf("Could not create file!\n"); + printf("Aborting process.\n"); + success=FALSE; + } + } + else + { + printf("Could not set read speed!\n"); + printf("Aborting process.\n"); + } + } + else + { + printf("Could not find lead-out entry in TOC to determine total sectors on CD!\n"); + printf("Aborting process.\n"); + success=FALSE; + } + } + else + { + printf("Could not read TOC!\n"); + printf("Aborting process.\n"); + } + } + else + { + printf("Drive is not ready!\n"); + printf("Aborting process.\n"); + } + + CloseHandle(hVolume); //Win32 function. + } + else + { + return FALSE; + } + + return success; +} + +void usage() +{ + printf("CDToImg v1.01. 22 Oct 2006.\n"); + printf("Usage: cdtoimg [x read speed]\n"); + printf("x speed is one of the following:\n"); + printf(" - Enter CD x speed value.\n"); + printf(" - Ommit or enter 0 to use currently set speed.\n"); + printf(" - Enter m for max speed.\n"); + return ; //Exit program here. +} + +int main(int argc, char *argv[]) +{ + unsigned short int x_speed; + + if((argc == 3) || (argc == 4)) + { + //65536 data transfer buffer. + data_buf=(unsigned char *)malloc(65536); + + if(argc == 3) + { + x_speed=0; //Use currently set write speed. + } + else + { + if(x_speed=argv[3][0]=='m') + { + x_speed=0xFFFF; //Use maximum write speed. + } + else + { + x_speed=atoi(argv[3]); //Use specified write speed. + } + } + if(read_cd_to_image(argv[1][0], argv[2], x_speed, 65536)) + { + printf("Process finished."); + } + else + { + printf("Could not create image from drive %c.", argv[1][0]); + } + + free(data_buf); + + return 0; + } + else + { + usage(); + return -1; //Exit program here. + } +} diff --git a/my_ntddscsi.h b/my_ntddscsi.h index a740232..b96f33f 100755 --- a/my_ntddscsi.h +++ b/my_ntddscsi.h @@ -1,56 +1,56 @@ -#ifndef MY_NTDDSCSI_H -#define MY_NTDDSCSI_H - -#include "spc.h" - -//** Defines taken from ntddscsi.h in MS Windows DDK CD -#define SCSI_IOCTL_DATA_OUT 0 //Give data to SCSI device (e.g. for writing) -#define SCSI_IOCTL_DATA_IN 1 //Get data from SCSI device (e.g. for reading) -#define SCSI_IOCTL_DATA_UNSPECIFIED 2 //No data (e.g. for ejecting) - -#define IOCTL_SCSI_PASS_THROUGH 0x4D004 -typedef struct _SCSI_PASS_THROUGH { - USHORT Length; - UCHAR ScsiStatus; - UCHAR PathId; - UCHAR TargetId; - UCHAR Lun; - UCHAR CdbLength; - UCHAR SenseInfoLength; - UCHAR DataIn; - ULONG DataTransferLength; - ULONG TimeOutValue; - ULONG_PTR DataBufferOffset; - ULONG SenseInfoOffset; - UCHAR Cdb[16]; -}SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH; - -#define IOCTL_SCSI_PASS_THROUGH_DIRECT 0x4D014 -typedef struct _SCSI_PASS_THROUGH_DIRECT { - USHORT Length; - UCHAR ScsiStatus; - UCHAR PathId; - UCHAR TargetId; - UCHAR Lun; - UCHAR CdbLength; - UCHAR SenseInfoLength; - UCHAR DataIn; - ULONG DataTransferLength; - ULONG TimeOutValue; - PVOID DataBuffer; - ULONG SenseInfoOffset; - UCHAR Cdb[16]; -}SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT; -//** End of defines taken from ntddscsi.h from MS Windows DDK CD - -typedef struct _SCSI_PASS_THROUGH_AND_BUFFERS { - SCSI_PASS_THROUGH spt; - BYTE DataBuffer[64*1024]; -}T_SPT_BUFS; - -typedef struct _SCSI_PASS_THROUGH_DIRECT_AND_SENSE_BUFFER { - SCSI_PASS_THROUGH_DIRECT sptd; - UCHAR SenseBuf[MAX_SENSE_LEN]; -}T_SPDT_SBUF; - -#endif \ No newline at end of file +#ifndef MY_NTDDSCSI_H +#define MY_NTDDSCSI_H + +#include "spc.h" + +//** Defines taken from ntddscsi.h in MS Windows DDK CD +#define SCSI_IOCTL_DATA_OUT 0 //Give data to SCSI device (e.g. for writing) +#define SCSI_IOCTL_DATA_IN 1 //Get data from SCSI device (e.g. for reading) +#define SCSI_IOCTL_DATA_UNSPECIFIED 2 //No data (e.g. for ejecting) + +#define IOCTL_SCSI_PASS_THROUGH 0x4D004 +typedef struct _SCSI_PASS_THROUGH { + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + ULONG_PTR DataBufferOffset; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +}SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH; + +#define IOCTL_SCSI_PASS_THROUGH_DIRECT 0x4D014 +typedef struct _SCSI_PASS_THROUGH_DIRECT { + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + PVOID DataBuffer; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +}SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT; +//** End of defines taken from ntddscsi.h from MS Windows DDK CD + +typedef struct _SCSI_PASS_THROUGH_AND_BUFFERS { + SCSI_PASS_THROUGH spt; + BYTE DataBuffer[64*1024]; +}T_SPT_BUFS; + +typedef struct _SCSI_PASS_THROUGH_DIRECT_AND_SENSE_BUFFER { + SCSI_PASS_THROUGH_DIRECT sptd; + UCHAR SenseBuf[MAX_SENSE_LEN]; +}T_SPDT_SBUF; + +#endif diff --git a/sam.h b/sam.h index a4ef2af..244eac8 100755 --- a/sam.h +++ b/sam.h @@ -1,22 +1,22 @@ -/* - SCSI-3 SCSI Architecture Model definitions (SAM), taken from SCSI-3 SAM1 draft. - Computer Programming Language: MS Visual Studio NET 2002 C/C++. - Author: Truman - Date written: 07 Aug 2005. -*/ -#ifndef SAM_H -#define SAM_H - -//SCSI return status codes. -#define STATUS_GOOD 0x00 // Status Good -#define STATUS_CHKCOND 0x02 // Check Condition -#define STATUS_CONDMET 0x04 // Condition Met -#define STATUS_BUSY 0x08 // Busy -#define STATUS_INTERM 0x10 // Intermediate -#define STATUS_INTCDMET 0x14 // Intermediate-condition met -#define STATUS_RESCONF 0x18 // Reservation conflict -#define STATUS_COMTERM 0x22 // Command Terminated -#define STATUS_QFULL 0x28 // Queue full -#define STATUS_ACA 0x30 // ACA active - -#endif \ No newline at end of file +/* + SCSI-3 SCSI Architecture Model definitions (SAM), taken from SCSI-3 SAM1 draft. + Computer Programming Language: MS Visual Studio NET 2002 C/C++. + Author: Truman + Date written: 07 Aug 2005. +*/ +#ifndef SAM_H +#define SAM_H + +//SCSI return status codes. +#define STATUS_GOOD 0x00 // Status Good +#define STATUS_CHKCOND 0x02 // Check Condition +#define STATUS_CONDMET 0x04 // Condition Met +#define STATUS_BUSY 0x08 // Busy +#define STATUS_INTERM 0x10 // Intermediate +#define STATUS_INTCDMET 0x14 // Intermediate-condition met +#define STATUS_RESCONF 0x18 // Reservation conflict +#define STATUS_COMTERM 0x22 // Command Terminated +#define STATUS_QFULL 0x28 // Queue full +#define STATUS_ACA 0x30 // ACA active + +#endif diff --git a/spc.h b/spc.h index d2551c0..b74ca43 100755 --- a/spc.h +++ b/spc.h @@ -1,51 +1,51 @@ -/* - SCSI-3 Primary Control definitions (SPC). 09 Oct 2006. - Definitions taken from SCSI-3 SPC1 draft. - Computer Programming Language: MS Visual Studio NET 2002 C/C++. - Author: Truman -*/ -#ifndef SPC_H -#define SPC_H - -#define MAX_SENSE_LEN 18 //Sense data max length -//Sense key codes.. -#define SEN_KEY_NO_SEN 0x00 //No sense key info. -#define SEN_KEY_NOT_READY 0x02 //Device not ready error. -#define SEN_KEY_ILLEGAL_REQ 0x05 //Illegal request, error/s in parameters or cmd. - -//CDB for test unit ready command -typedef struct -{ - unsigned char cmd; - unsigned char reserved1; - unsigned char reserved2; - unsigned char reserved3; - unsigned char reserved4; - unsigned char control; -}T_test_unit_ready; - -//Request sense return data format -typedef struct -{ - unsigned char response_code; - unsigned char segment_no; - unsigned char flags_sensekey; - unsigned char info0; - unsigned char info1; - unsigned char info2; - unsigned char info3; - unsigned char add_len; - unsigned char com_spec_info0; - unsigned char com_spec_info1; - unsigned char com_spec_info2; - unsigned char com_spec_info3; - unsigned char ASC; - unsigned char ASCQ; - unsigned char field_rep_ucode; - unsigned char sen_key_spec15; - unsigned char sen_key_spec16; - unsigned char sen_key_spec17; - unsigned char add_sen_bytes; -}T_sense_data; - -#endif \ No newline at end of file +/* + SCSI-3 Primary Control definitions (SPC). 09 Oct 2006. + Definitions taken from SCSI-3 SPC1 draft. + Computer Programming Language: MS Visual Studio NET 2002 C/C++. + Author: Truman +*/ +#ifndef SPC_H +#define SPC_H + +#define MAX_SENSE_LEN 18 //Sense data max length +//Sense key codes.. +#define SEN_KEY_NO_SEN 0x00 //No sense key info. +#define SEN_KEY_NOT_READY 0x02 //Device not ready error. +#define SEN_KEY_ILLEGAL_REQ 0x05 //Illegal request, error/s in parameters or cmd. + +//CDB for test unit ready command +typedef struct +{ + unsigned char cmd; + unsigned char reserved1; + unsigned char reserved2; + unsigned char reserved3; + unsigned char reserved4; + unsigned char control; +}T_test_unit_ready; + +//Request sense return data format +typedef struct +{ + unsigned char response_code; + unsigned char segment_no; + unsigned char flags_sensekey; + unsigned char info0; + unsigned char info1; + unsigned char info2; + unsigned char info3; + unsigned char add_len; + unsigned char com_spec_info0; + unsigned char com_spec_info1; + unsigned char com_spec_info2; + unsigned char com_spec_info3; + unsigned char ASC; + unsigned char ASCQ; + unsigned char field_rep_ucode; + unsigned char sen_key_spec15; + unsigned char sen_key_spec16; + unsigned char sen_key_spec17; + unsigned char add_sen_bytes; +}T_sense_data; + +#endif