diff --git a/DiscImageChef.Device.Report/CMakeLists.txt b/DiscImageChef.Device.Report/CMakeLists.txt index e3df77cf0..12c3de578 100644 --- a/DiscImageChef.Device.Report/CMakeLists.txt +++ b/DiscImageChef.Device.Report/CMakeLists.txt @@ -7,5 +7,5 @@ find_package(LibXml2) include_directories(${LIBXML2_INCLUDE_DIR}) -add_executable(DiscImageChef_Device_Report main.c scsi.c scsi.h main.h ata.h ata.c atapi.c atapi.h atapi_report.c atapi_report.h identify_decode.c identify_decode.h scsi_report.c scsi_report.h inquiry_decode.c inquiry_decode.h scsi_mode.h scsi_mode.c) +add_executable(DiscImageChef_Device_Report main.c scsi.c scsi.h main.h ata.h ata.c atapi.c atapi.h atapi_report.c atapi_report.h identify_decode.c identify_decode.h scsi_report.c scsi_report.h inquiry_decode.c inquiry_decode.h scsi_mode.h scsi_mode.c mmc_report.c mmc_report.h cdrom_mode.h) target_link_libraries(DiscImageChef_Device_Report ${LIBXML2_LIBRARIES}) \ No newline at end of file diff --git a/DiscImageChef.Device.Report/cdrom_mode.h b/DiscImageChef.Device.Report/cdrom_mode.h new file mode 100644 index 000000000..1a69b733a --- /dev/null +++ b/DiscImageChef.Device.Report/cdrom_mode.h @@ -0,0 +1,114 @@ +// +// Created by claunia on 17/12/17. +// + +#ifndef DISCIMAGECHEF_DEVICE_REPORT_CDROM_MODE_H +#define DISCIMAGECHEF_DEVICE_REPORT_CDROM_MODE_H + +#pragma pack(push, 1) +typedef struct +{ + uint8_t Reserved1; + uint8_t RotationControl : 3; + uint8_t Reserved2 : 5; + uint16_t WriteSpeed; +} ModePage_2A_WriteDescriptor; +#pragma pack(pop) + +#pragma pack(push, 1) +typedef struct +{ + uint8_t PageCode : 6; + uint8_t Reserved1 : 1; +/* Parameters can be saved */ + uint8_t PS : 1; + uint8_t PageLength; + uint8_t ReadCDR : 1; + uint8_t ReadCDRW : 1; + uint8_t Method2 : 1; + uint8_t ReadDVDROM : 1; + uint8_t ReadDVDR : 1; + uint8_t ReadDVDRAM : 1; + uint8_t Reserved2 : 2; + uint8_t WriteCDR : 1; + uint8_t WriteCDRW : 1; + uint8_t TestWrite : 1; + uint8_t Reserved3 : 1; + uint8_t WriteDVDR : 1; + uint8_t WriteDVDRAM : 1; + uint8_t Reserved4 : 2; +/* Drive is capable of playing audio */ + uint8_t AudioPlay : 1; + uint8_t Composite : 1; + uint8_t DigitalPort1 : 1; + uint8_t DigitalPort2 : 1; +/* Drive is capable of reading sectors in Mode 2 Form 1 format */ + uint8_t Mode2Form1 : 1; +/* Drive is capable of reading sectors in Mode 2 Form 2 format */ + uint8_t Mode2Form2 : 1; + /* Drive supports multi-session and/or Photo-CD */ + uint8_t MultiSession : 1; + uint8_t BUF : 1; +/* Audio can be read as digital data */ + uint8_t CDDACommand : 1; +/* Drive can continue from a loss of streaming on audio reading */ + uint8_t AccurateCDDA : 1; +/* Drive can read interleaved and uncorrected R-W subchannels */ + uint8_t Subchannel : 1; +/* Drive can read, deinterlave and correct R-W subchannels */ + uint8_t DeinterlaveSubchannel : 1; +/* Drive can return C2 pointers */ + uint8_t C2Pointer : 1; +/* Drive can return the media catalogue number */ + uint8_t UPC : 1; +/* Drive can return the ISRC */ + uint8_t ISRC : 1; + uint8_t ReadBarcode : 1; + /* Drive can lock media */ + uint8_t Lock : 1; +/* Current lock status */ + uint8_t LockState : 1; +/* Drive's optional prevent jumper status */ + uint8_t PreventJumper : 1; +/* Drive can eject discs */ + uint8_t Eject : 1; + uint8_t Reserved5 : 1; + /* Loading Mechanism Type */ + uint8_t LoadingMechanism : 3; + /* Each channel's volume can be controlled independently */ + uint8_t SeparateChannelVolume : 1; +/* Each channel can be muted independently */ + uint8_t SeparateChannelMute : 1; + uint8_t SDP : 1; + uint8_t SSS : 1; + uint8_t SCC : 1; + uint8_t LeadInPW : 1; + uint8_t Reserved6 : 2; +/* Maximum drive speed in Kbytes/second */ + uint16_t MaximumSpeed ; +/* Supported volume levels */ + uint16_t SupportedVolumeLevels; +/* Buffer size in Kbytes */ + uint16_t BufferSize; +/* Current drive speed in Kbytes/second */ + uint16_t CurrentSpeed; + uint8_t Reserved7; + uint8_t Reserved8 : 1; + uint8_t BCK : 1; + uint8_t RCK : 1; + uint8_t LSBF : 1; + uint8_t Length : 2; + uint8_t Reserved9 : 2; + uint16_t MaxWriteSpeed; + uint16_t CurrentWriteSpeed; + uint16_t CMRSupported; + uint8_t Reserved10[3]; + uint8_t RotationControlSelected : 2; + uint8_t Reserved11 : 6; + uint16_t CurrentWriteSpeedSelected; + uint16_t LogicalWriteSpeedDescriptors; + ModePage_2A_WriteDescriptor WriteSpeedPerformanceDescriptors[56]; +} ModePage_2A; +#pragma pack(pop) + +#endif //DISCIMAGECHEF_DEVICE_REPORT_CDROM_MODE_H diff --git a/DiscImageChef.Device.Report/mmc_report.c b/DiscImageChef.Device.Report/mmc_report.c new file mode 100644 index 000000000..13640064c --- /dev/null +++ b/DiscImageChef.Device.Report/mmc_report.c @@ -0,0 +1,1627 @@ +// +// Created by claunia on 17/12/17. +// + +#include +#include +#include +#include +#include "mmc_report.h" +#include "cdrom_mode.h" +#include "scsi.h" +#include "scsi_mode.h" + +SeparatedFeatures Separate(unsigned char* response); + +void MmcReport(int fd, xmlTextWriterPtr xmlWriter, unsigned char* cdromMode) +{ + unsigned char *sense = NULL; + unsigned char *buffer = NULL; + int i, error, len; + char user_response = ' '; + int audio_cd = FALSE, cd_rom = FALSE, cd_r = FALSE, cd_rw = FALSE; + int ddcd_rom = FALSE, ddcd_r = FALSE, ddcd_rw = FALSE; + int dvd_rom = FALSE, dvd_ram = FALSE, dvd_r = FALSE, dvd_rw = FALSE; + int cd_mrw = FALSE, dvd_p_mrw = FALSE; + int dvd_p_r = FALSE, dvd_p_rw = FALSE, dvd_p_r_dl = FALSE, dvd_p_rw_dl = FALSE; + int dvd_r_dl = FALSE, dvd_rw_dl = FALSE; + int hd_dvd_rom = FALSE, hd_dvd_ram = FALSE, hd_dvd_r = FALSE, hd_dvd_rw = FALSE; + int bd_re = FALSE, bd_rom = FALSE, bd_r = FALSE, bd_re_lth = FALSE, bd_r_lth = FALSE; + int bd_re_xl = FALSE, bd_r_xl = FALSE; + + xmlTextWriterStartElement(xmlWriter, BAD_CAST "MultiMediaDevice"); // + + if(cdromMode != NULL && (cdromMode[0] & 0x3F) == 0x2A) + { + len = cdromMode[1] + 2; + ModePage_2A cdmode; + memset(&cdmode, 0, sizeof(ModePage_2A)); + memcpy(&cdmode, cdromMode, len > sizeof(ModePage_2A) ? sizeof(ModePage_2A) : len); + + xmlTextWriterStartElement(xmlWriter, BAD_CAST "ModeSense2A"); // + + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "AccurateCDDA", "%s", cdmode.AccurateCDDA ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "BCK", "%s", cdmode.BCK ? "true" : "false"); + if(cdmode.BufferSize != 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "BufferSize", "%d", be16toh(cdmode.BufferSize)); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "BufferUnderRunProtection", "%s", cdmode.BUF ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanEject", "%s", cdmode.Eject ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanLockMedia", "%s", cdmode.Lock ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CDDACommand", "%s", cdmode.CDDACommand ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CompositeAudioVideo", "%s", cdmode.Composite ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CSSandCPPMSupported", "%s", cdmode.CMRSupported == 1 ? "true" : "false"); + if(cdmode.CurrentSpeed != 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CurrentSpeed", "%d", be16toh(cdmode.CurrentSpeed)); + if(cdmode.CurrentWriteSpeed != 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CurrentWriteSpeed", "%d", be16toh(cdmode.CurrentWriteSpeed)); + if(cdmode.CurrentWriteSpeedSelected != 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CurrentWriteSpeedSelected", "%d", be16toh(cdmode.CurrentWriteSpeedSelected)); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "DeterministicSlotChanger", "%s", cdmode.SDP ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "DigitalPort1", "%s", cdmode.DigitalPort1 ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "DigitalPort2", "%s", cdmode.DigitalPort2 ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "LeadInPW", "%s", cdmode.LeadInPW ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "LoadingMechanismType", "%d", cdmode.LoadingMechanism); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "LockStatus", "%s", cdmode.LockState ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "LSBF", "%s", cdmode.LSBF ? "true" : "false"); + if(cdmode.MaximumSpeed != 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "MaximumSpeed", "%d", be16toh(cdmode.MaximumSpeed)); + if(cdmode.MaxWriteSpeed != 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "MaximumWriteSpeed", "%d", be16toh(cdmode.MaxWriteSpeed)); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "PlaysAudio", "%s", cdmode.AudioPlay ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "PreventJumperStatus", "%s", cdmode.PreventJumper ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "RCK", "%s", cdmode.RCK ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ReadsBarcode", "%s", cdmode.ReadBarcode ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ReadsBothSides", "%s", cdmode.SCC ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ReadsCDR", "%s", cdmode.ReadCDR ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ReadsCDRW", "%s", cdmode.ReadCDRW ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ReadsDeinterlavedSubchannel", "%s", cdmode.DeinterlaveSubchannel ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ReadsDVDR", "%s", cdmode.ReadDVDR ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ReadsDVDRAM", "%s", cdmode.ReadDVDRAM ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ReadsDVDROM", "%s", cdmode.ReadDVDROM ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ReadsISRC", "%s", cdmode.ISRC ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ReadsMode2Form2", "%s", cdmode.Mode2Form2 ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ReadsMode2Form1", "%s", cdmode.Mode2Form1 ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ReadsPacketCDR", "%s", cdmode.Method2 ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ReadsSubchannel", "%s", cdmode.Subchannel ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ReadsUPC", "%s", cdmode.UPC ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ReturnsC2Pointers", "%s", cdmode.C2Pointer ? "true" : "false"); + if(cdmode.RotationControlSelected != 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "RotationControlSelected", "%d", be16toh(cdmode.RotationControlSelected)); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SeparateChannelMute", "%s", cdmode.SeparateChannelMute ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SeparateChannelVolume", "%s", cdmode.SeparateChannelVolume ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SSS", "%s", cdmode.SSS ? "true" : "false"); + if(cdmode.SupportedVolumeLevels != 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportedVolumeLevels", "%d", be16toh(cdmode.SupportedVolumeLevels)); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsMultiSession", "%s", cdmode.MultiSession ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "TestWrite", "%s", cdmode.TestWrite ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "WritesCDR", "%s", cdmode.WriteCDR ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "WritesCDRW", "%s", cdmode.WriteCDRW ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "WritesDVDR", "%s", cdmode.WriteDVDR ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "WritesDVDRAM", "%s", cdmode.WriteDVDRAM ? "true" : "false"); + + len -= 32; // Remove non descriptors size + len /= 4; // Each descriptor takes 4 bytes + + for(i = 0; i < len; i++) + { + if(be16toh(cdmode.WriteSpeedPerformanceDescriptors[i].WriteSpeed) != 0) + { + xmlTextWriterStartElement(xmlWriter, + BAD_CAST "ModePage_2A_WriteDescriptor"); // + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "RotationControl", "%d", + be16toh(cdmode.WriteSpeedPerformanceDescriptors[i].RotationControl)); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "WriteSpeed", "%d", + be16toh(cdmode.WriteSpeedPerformanceDescriptors[i].WriteSpeed)); + xmlTextWriterEndElement(xmlWriter); // + } + } + + xmlTextWriterEndElement(xmlWriter); // + + cd_rom = TRUE; + audio_cd = TRUE; + cd_r = cdmode.ReadCDR; + cd_rw = cdmode.ReadCDRW; + dvd_rom = cdmode.ReadDVDROM; + dvd_ram = cdmode.ReadDVDRAM; + dvd_r = cdmode.ReadDVDR; + } + + printf("Querying MMC GET CONFIGURATION...\n"); + error = GetConfiguration(fd, &buffer, &sense, 0x0000, 0x00); + + if(!error) + { + SeparatedFeatures ftr = Separate(buffer); + + uint16_t knownFeatures[] = { 0x0001, 0x0003, 0x0004, 0x0010, 0x001D, 0x001E, 0x001F, 0x0022, 0x0023, 0x0024, + 0x0027, 0x0028, 0x002A, 0x002B, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, 0x0032, + 0x0037, 0x0038, 0x003A, 0x003B, 0x0040, 0x0041, 0x0050, 0x0051, 0x0080, 0x0101, + 0x0102, 0x0103, 0x0104, 0x0106, 0x0108, 0x0109, 0x010B, 0x010C, 0x010D, 0x010E, + 0x0113, 0x0142, 0x0110}; + xmlTextWriterStartElement(xmlWriter, BAD_CAST "Features"); // + + for(i = 0; i < sizeof(knownFeatures) / sizeof(uint16_t); i++) + { + uint16_t currentCode = knownFeatures[i]; + switch(currentCode) + { + case 0x0001: + { + if(ftr.Descriptors[currentCode].data != NULL) + { + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 0) + { + uint32_t physicalInterface = (ftr.Descriptors[currentCode].data[4] << 24) + (ftr.Descriptors[currentCode].data[5] << 16) + (ftr.Descriptors[currentCode].data[6] << 8) + ftr.Descriptors[currentCode].data[7]; + switch(physicalInterface) + { + case 0: + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "PhysicalInterfaceStandard", "%s", "Unspecified"); + break; + case 1: + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "PhysicalInterfaceStandard", "%s", "SCSI"); + break; + case 2: + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "PhysicalInterfaceStandard", "%s", "ATAPI"); + break; + case 3: + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "PhysicalInterfaceStandard", "%s", "IEEE1394"); + break; + case 4: + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "PhysicalInterfaceStandard", "%s", "IEEE1394A"); + break; + case 5: + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "PhysicalInterfaceStandard", "%s", "FC"); + break; + case 6: + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "PhysicalInterfaceStandard", "%s", "IEEE1394B"); + break; + case 7: + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "PhysicalInterfaceStandard", "%s", "SerialATAPI"); + break; + case 8: + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "PhysicalInterfaceStandard", "%s", "USB"); + break; + case 0xFFFF: + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "PhysicalInterfaceStandard", "%s", "Vendor"); + break; + default: + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "PhysicalInterfaceStandard", "%s", "Unspecified"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "PhysicalInterfaceStandardNumber", "%d", physicalInterface); + break; + } + } + break; + } + case 0x0003: + { + if(ftr.Descriptors[currentCode].data != NULL) + { + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 0) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "LoadingMechanismType", "%d", (ftr.Descriptors[currentCode].data[4] & 0xE0) >> 5); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanEject", "%s", (ftr.Descriptors[currentCode].data[4] & 0x08) ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "PreventJumper", "%s", (ftr.Descriptors[currentCode].data[4] & 0x04) ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "Locked", "%s", (ftr.Descriptors[currentCode].data[4] & 0x01) ? "true" : "false"); + } + + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 2) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanLoad", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x10) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "DBML", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x02) + ? "true" : "false"); + } + } + break; + } + case 0x0004: + { + if(ftr.Descriptors[currentCode].data != NULL) + { + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 0) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsPWP", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x02) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsSWPP", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x01) + ? "true" : "false"); + } + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 1) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsWriteInhibitDCB", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x04) + ? "true" : "false"); + + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 2) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsWriteProtectPAC", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x08) + ? "true" : "false"); + } + break; + } + case 0x0010: + { + if(ftr.Descriptors[currentCode].data != NULL) + { + uint32_t LogicalBlockSize = (uint32_t)((ftr.Descriptors[currentCode].data[4] << 24) + (ftr.Descriptors[currentCode].data[5] << 16) + (ftr.Descriptors[currentCode].data[6] << 8) + ftr.Descriptors[currentCode].data[7]); + uint16_t Blocking = (uint16_t)((ftr.Descriptors[currentCode].data[8] << 8) + ftr.Descriptors[currentCode].data[9]); + if(LogicalBlockSize > 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "LogicalBlockSize", "%d", LogicalBlockSize); + if(Blocking > 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "BlocksPerReadableUnit", "%d",Blocking); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ErrorRecoveryPage", "%s", + (ftr.Descriptors[currentCode].data[10] & 0x01) + ? "true" : "false"); + } + break; + } + case 0x001D: + { + if(ftr.Descriptors[currentCode].present) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "MultiRead", "%s", "true"); + cd_r = TRUE; + cd_rom = TRUE; + cd_rw = TRUE; + } + break; + } + case 0x001E: + { + if(ftr.Descriptors[currentCode].present) + { + cd_rom = TRUE; + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadCD", "%s", "true"); + + if(ftr.Descriptors[currentCode].data != NULL) + { + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 0) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsC2", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x02) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadLeadInCDText", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x01) + ? "true" : "false"); + } + + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 2) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsDAP", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x80) + ? "true" : "false"); + } + } + break; + } + case 0x001F: + { + if(ftr.Descriptors[currentCode].present) + { + dvd_rom = TRUE; + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadDVD", "%s", "true"); + + if(ftr.Descriptors[currentCode].data != NULL) + { + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 2) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "DVDMultiRead", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x01) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadAllDualR", "%s", + (ftr.Descriptors[currentCode].data[6] & 0x01) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadAllDualRW", "%s", + (ftr.Descriptors[currentCode].data[6] & 0x02) + ? "true" : "false"); + + if(ftr.Descriptors[currentCode].data[4] & 0x01) + { + cd_r = TRUE; + cd_rom = TRUE; + cd_rw = TRUE; + } + if(ftr.Descriptors[currentCode].data[6] & 0x01) + dvd_r_dl = TRUE; + if(ftr.Descriptors[currentCode].data[6] & 0x02) + dvd_rw_dl = TRUE; + } + } + } + break; + } + case 0x0022: + { + if(ftr.Descriptors[currentCode].present) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanEraseSector", "%s", "true"); + break; + } + case 0x0023: + { + if(ftr.Descriptors[currentCode].present) + { + bd_re = TRUE; + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanFormat", "%s", "true"); + + if(ftr.Descriptors[currentCode].data != NULL) + { + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 1) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanFormatBDREWithoutSpare", + "%s", + (ftr.Descriptors[currentCode].data[4] & 0x08) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanExpandBDRESpareArea", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x04) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanFormatQCert", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x02) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanFormatCert", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x01) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanFormatRRM", "%s", + (ftr.Descriptors[currentCode].data[8] & 0x01) + ? "true" : "false"); + } + + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 2) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanFormatFRF", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x80) + ? "true" : "false"); + } + } + break; + } + case 0x0024: + { + if(ftr.Descriptors[currentCode].present) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadSpareAreaInformation", "%s", "true"); + break; + } + case 0x0027: + { + if(ftr.Descriptors[currentCode].present) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteCDRWCAV", "%s", "true"); + cd_rw = TRUE; + } + break; + } + case 0x0028: + { + if(ftr.Descriptors[currentCode].present) + { + cd_mrw = TRUE; + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadCDMRW", "%s", "true"); + + if(ftr.Descriptors[currentCode].data != NULL) + { + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteCDMRW", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x01) + ? "true" : "false"); + + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 1) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteDVDPlusMRW", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x04) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadDVDPlusMRW", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x02) + ? "true" : "false"); + + if(ftr.Descriptors[currentCode].data[4] & 0x02) + dvd_p_mrw = TRUE; + } + } + } + break; + } + case 0x002A: + { + if(ftr.Descriptors[currentCode].present) + { + dvd_p_rw = TRUE; + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadDVDPlusRW", "%s", "true"); + + if(ftr.Descriptors[currentCode].data != NULL) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteDVDPlusRW", "%s", (ftr.Descriptors[currentCode].data[4] & 0x01) ? "true" : "false"); + } + break; + } + case 0x002B: + { + if(ftr.Descriptors[currentCode].present) + { + dvd_p_r = TRUE; + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadDVDPlusR", "%s", "true"); + + if(ftr.Descriptors[currentCode].data != NULL) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteDVDPlusR", "%s", (ftr.Descriptors[currentCode].data[4] & 0x01) ? "true" : "false"); + } + break; + } + case 0x002D: + { + if(ftr.Descriptors[currentCode].present) + { + cd_r = TRUE; + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadCDMRW", "%s", "true"); + + if(ftr.Descriptors[currentCode].data != NULL) + { + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 0) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanTestWriteInTAO", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x04) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanOverwriteTAOTrack", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x02) + ? "true" : "false"); + if(ftr.Descriptors[currentCode].data[4] & 0x02) + cd_rw = TRUE; + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteRWSubchannelInTAO", + "%s", + (ftr.Descriptors[currentCode].data[4] & 0x01) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "DataTypeSupported", "%d", + (ftr.Descriptors[currentCode].data[6] << 8) + + ftr.Descriptors[currentCode].data[7]); + } + + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 2) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "BufferUnderrunFreeInTAO", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x40) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteRawSubchannelInTAO", + "%s", + (ftr.Descriptors[currentCode].data[4] & 0x10) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWritePackedSubchannelInTAO", + "%s", + (ftr.Descriptors[currentCode].data[4] & 0x08) + ? "true" : "false"); + } + } + } + break; + } + case 0x002E: + { + if(ftr.Descriptors[currentCode].present) + { + cd_r = TRUE; + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadCDMRW", "%s", "true"); + + if(ftr.Descriptors[currentCode].data != NULL) + { + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 0) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteRawMultiSession", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x10) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteRaw", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x08) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanTestWriteInSAO", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x04) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanOverwriteSAOTrack", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x02) + ? "true" : "false"); + if(ftr.Descriptors[currentCode].data[4] & 0x02) + cd_rw = TRUE; + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteRWSubchannelInSAO", + "%s", + (ftr.Descriptors[currentCode].data[4] & 0x01) + ? "true" : "false"); + } + + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 1) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "BufferUnderrunFreeInSAO", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x40) + ? "true" : "false"); + } + } + } + break; + } + case 0x002F: + { + if(ftr.Descriptors[currentCode].present) + { + dvd_r = TRUE; + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteDVDR", "%s", "true"); + + if(ftr.Descriptors[currentCode].data != NULL) + { + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 0) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "BufferUnderrunFreeInDVD", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x40) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanTestWriteDVD", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x04) + ? "true" : "false"); + } + + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 1) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteDVDRW", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x02) + ? "true" : "false"); + + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 2) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteDVDRDL", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x08) + ? "true" : "false"); + } + } + break; + } + case 0x0030: + { + if(ftr.Descriptors[currentCode].present) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadDDCD", "%s", "true"); + ddcd_rom = TRUE; + } + break; + } + case 0x0031: + { + if(ftr.Descriptors[currentCode].present) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteDDCDR", "%s", "true"); + ddcd_r = TRUE; + + if(ftr.Descriptors[currentCode].data != NULL) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanTestWriteDDCDR", "%s", (ftr.Descriptors[currentCode].data[4] & 0x04) ? "true" : "false"); + } + break; + } + case 0x0032: + { + if(ftr.Descriptors[currentCode].present) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteDDCDRW", "%s", "true"); + ddcd_rw = TRUE; + } + break; + } + case 0x0037: + { + if(ftr.Descriptors[currentCode].present) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteCDRW", "%s", "true"); + cd_rw = TRUE; + } + break; + } + case 0x0038: + { + if(ftr.Descriptors[currentCode].present) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanPseudoOverwriteBDR", "%s", "true"); + bd_r = TRUE; + } + break; + } + case 0x003A: + { + if(ftr.Descriptors[currentCode].present) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadDVDPlusRWDL", "%s", "true"); + dvd_p_rw_dl = TRUE; + + if(ftr.Descriptors[currentCode].data != NULL) + { + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteDVDPlusRWDL", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x01) + ? "true" : "false"); + } + } + break; + } + case 0x003B: + { + if(ftr.Descriptors[currentCode].present) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadDVDPlusRDL", "%s", "true"); + dvd_p_r_dl = TRUE; + + if(ftr.Descriptors[currentCode].data != NULL) + { + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteDVDPlusRDL", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x01) + ? "true" : "false"); + } + } + break; + } + case 0x0040: + { + if(ftr.Descriptors[currentCode].present) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadBD", "%s", "true"); + bd_rom = TRUE; + + if(ftr.Descriptors[currentCode].data != NULL) + { + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 0) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadOldBDRE", "%s", + (ftr.Descriptors[currentCode].data[9] & 0x01) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadOldBDR", "%s", + (ftr.Descriptors[currentCode].data[17] & 0x01) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadOldBDROM", "%s", + (ftr.Descriptors[currentCode].data[25] & 0x01) + ? "true" : "false"); + } + + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 1) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadBluBCA", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x01) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadBDRE2", "%s", + (ftr.Descriptors[currentCode].data[9] & 0x04) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadBDRE1", "%s", + (ftr.Descriptors[currentCode].data[9] & 0x02) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadBDR", "%s", + (ftr.Descriptors[currentCode].data[17] & 0x02) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadBDROM", "%s", + (ftr.Descriptors[currentCode].data[25] & 0x02) + ? "true" : "false"); + } + } + } + break; + } + case 0x0041: + { + if(ftr.Descriptors[currentCode].present) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteBD", "%s", "true"); + bd_rom = TRUE; + + if(ftr.Descriptors[currentCode].data != NULL) + { + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 0) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteOldBDRE", "%s", + (ftr.Descriptors[currentCode].data[9] & 0x01) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteOldBDR", "%s", + (ftr.Descriptors[currentCode].data[17] & 0x01) + ? "true" : "false"); + } + + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 1) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteBDRE2", "%s", + (ftr.Descriptors[currentCode].data[9] & 0x04) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteBDRE1", "%s", + (ftr.Descriptors[currentCode].data[9] & 0x02) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadBDR", "%s", + (ftr.Descriptors[currentCode].data[17] & 0x02) + ? "true" : "false"); + } + } + } + break; + } + case 0x0050: + { + if(ftr.Descriptors[currentCode].present) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadHDDVD", "%s", "true"); + hd_dvd_rom = TRUE; + + if(ftr.Descriptors[currentCode].data != NULL) + { + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 0) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadHDDVDR", "%s", + (ftr.Descriptors[currentCode].data[9] & 0x01) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadHDDVDRAM", "%s", + (ftr.Descriptors[currentCode].data[6] & 0x01) + ? "true" : "false"); + if(ftr.Descriptors[currentCode].data[6] & 0x01) + hd_dvd_ram = TRUE; + } + } + } + break; + } + case 0x0051: + { + if(ftr.Descriptors[currentCode].present) + { + hd_dvd_rom = TRUE; + + if(ftr.Descriptors[currentCode].data != NULL) + { + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 0) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadHDDVDR", "%s", + (ftr.Descriptors[currentCode].data[9] & 0x01) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteHDDVDRAM", "%s", + (ftr.Descriptors[currentCode].data[6] & 0x01) + ? "true" : "false"); + if(ftr.Descriptors[currentCode].data[6] & 0x01) + hd_dvd_ram = TRUE; + } + } + } + break; + } + case 0x0080: + { + if(ftr.Descriptors[currentCode].present) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsHybridDiscs", "%s", "true"); + break; + } + case 0x0101: + { + if(ftr.Descriptors[currentCode].present) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsModePage1Ch", "%s", "true"); + break; + } + case 0x0102: + { + if(ftr.Descriptors[currentCode].present) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "EmbeddedChanger", "%s", "true"); + + if(ftr.Descriptors[currentCode].data != NULL) + { + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 0) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ChangerIsSideChangeCapable", + "%s", + (ftr.Descriptors[currentCode].data[4] & 0x10) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ChangerSupportsDiscPresent", + "%s", + (ftr.Descriptors[currentCode].data[4] & 0x04) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "HighestSlotNumber", "%d", + (ftr.Descriptors[currentCode].data[7] & 0x1F) + + 1); + } + } + } + break; + } + case 0x0103: + { + if(ftr.Descriptors[currentCode].present) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanPlayCDAudio", "%s", "true"); + audio_cd = TRUE; + + if(ftr.Descriptors[currentCode].data != NULL) + { + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 0) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanAudioScan", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x10) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanMuteSeparateChannels", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x04) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsSeparateVolume", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x04) + ? "true" : "false"); + + uint16_t volumeLevels = (uint16_t)( + (ftr.Descriptors[currentCode].data[6] << 8) + + ftr.Descriptors[currentCode].data[7]); + if(volumeLevels > 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "VolumeLevels", "%d", + volumeLevels); + } + } + } + break; + } + case 0x0104: + { + if(ftr.Descriptors[currentCode].present) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanUpgradeFirmware", "%s", "true"); + break; + } + case 0x0106: + { + if(ftr.Descriptors[currentCode].present) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsCSS", "%s", "true"); + + if(ftr.Descriptors[currentCode].data != NULL) + { + if(ftr.Descriptors[currentCode].data[7] > 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CSSVersion", "%d", + ftr.Descriptors[currentCode].data[7]); + } + } + break; + } + case 0x0108: + { + if(ftr.Descriptors[currentCode].present) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReportDriveSerial", "%s", "true"); + break; + } + case 0x0109: + { + if(ftr.Descriptors[currentCode].present) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReportMediaSerial", "%s", "true"); + break; + } + case 0x010B: + { + if(ftr.Descriptors[currentCode].present) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsCPRM", "%s", "true"); + + if(ftr.Descriptors[currentCode].data != NULL) + { + if(ftr.Descriptors[currentCode].data[7] > 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CPRMVersion", "%d", + ftr.Descriptors[currentCode].data[7]); + } + } + break; + } + case 0x010C: + { + if(ftr.Descriptors[currentCode].present && ftr.Descriptors[currentCode].data != NULL) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "FirmwareDate", "%c%c%c%c-%c%c-%c%c", + ftr.Descriptors[currentCode].data[4], ftr.Descriptors[currentCode].data[5], + ftr.Descriptors[currentCode].data[6], ftr.Descriptors[currentCode].data[7], + ftr.Descriptors[currentCode].data[8], ftr.Descriptors[currentCode].data[9], + ftr.Descriptors[currentCode].data[10], ftr.Descriptors[currentCode].data[11]); + } + break; + } + case 0x010D: + { + if(ftr.Descriptors[currentCode].present) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsAACS", "%s", "true"); + + if(ftr.Descriptors[currentCode].data != NULL) + { + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 0) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanGenerateBindingNonce", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x01) + ? "true" : "false"); + if(ftr.Descriptors[currentCode].data[5] > 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "BindNonceBlocks", "%d", + (int8_t)ftr.Descriptors[currentCode].data[5]); + if((ftr.Descriptors[currentCode].data[6] & 0x0F) > 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "AGIDs", "%d", + ftr.Descriptors[currentCode].data[6] & + 0x0F); + if(ftr.Descriptors[currentCode].data[7] > 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "AACSVersion", "%d", + (int8_t)ftr.Descriptors[currentCode].data[7]); + } + + if(((ftr.Descriptors[currentCode].data[2] & 0x3C) >> 2) >= 2) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadDriveAACSCertificate", + "%s", + (ftr.Descriptors[currentCode].data[4] & 0x10) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadCPRM_MKB", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x08) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteBusEncryptedBlocks", + "%s", + (ftr.Descriptors[currentCode].data[4] & 0x04) + ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsBusEncryption", "%s", + (ftr.Descriptors[currentCode].data[4] & 0x02) + ? "true" : "false"); + } + } + } + break; + } + case 0x010E: + { + if(ftr.Descriptors[currentCode].present) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanWriteCSSManagedDVD", "%s", "true"); + break; + } + case 0x0113: + { + if(ftr.Descriptors[currentCode].present) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsSecurDisc", "%s", "true"); + break; + } + case 0x0142: + { + if(ftr.Descriptors[currentCode].present) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsOSSC", "%s", "true"); + break; + } + case 0x0110: + { + if(ftr.Descriptors[currentCode].present) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsVCPS", "%s", "true"); + break; + } + } + } + } + + xmlTextWriterEndElement(xmlWriter); // + } + + if(!audio_cd && !cd_rom && !cd_r && !cd_rw && !ddcd_rom && !ddcd_r && !ddcd_rw && !dvd_rom && !dvd_ram && !dvd_r && !dvd_rw && !cd_mrw && !dvd_p_mrw && !dvd_p_r && !dvd_p_rw && !dvd_p_r_dl && !dvd_p_rw_dl && !dvd_r_dl && !dvd_rw_dl && !hd_dvd_rom && !hd_dvd_ram && !hd_dvd_r && !hd_dvd_rw && !bd_re && !bd_rom && !bd_r && !bd_re_lth && !bd_r_lth && !bd_re_xl && !bd_r_xl) + cd_rom = TRUE; + + if(bd_rom) + { + bd_rom = TRUE; + bd_r = TRUE; + bd_re = TRUE; + bd_r_lth = TRUE; + bd_r_xl = TRUE; + } + + if(cd_rom) + { + audio_cd = TRUE; + cd_rom = TRUE; + cd_r = TRUE; + cd_rw = TRUE; + } + + if(ddcd_rom) + { + ddcd_rom = TRUE; + ddcd_r = TRUE; + ddcd_rw = TRUE; + } + + if(dvd_rom) + { + dvd_rom = TRUE; + dvd_r = TRUE; + dvd_rw = TRUE; + dvd_p_r = TRUE; + dvd_p_rw = TRUE; + dvd_p_r_dl = TRUE; + dvd_r_dl = TRUE; + } + + if(hd_dvd_rom) + { + hd_dvd_rom = TRUE; + hd_dvd_ram = TRUE; + hd_dvd_r = TRUE; + hd_dvd_rw = TRUE; + } + + int tryPlextor = FALSE, tryHLDTST = FALSE, tryPioneer = FALSE, tryNEC = FALSE; + + // Do not change order!!! + const char *mediaNamesArray[] = {"Audio CD" /*0*/, "BD-R" /*1*/, "BD-RE" /*2*/, "BD-R LTH" /*3*/, "BD-R XL" /*4*/, + "BD-ROM" /*5*/, "CD-MRW" /*6*/, "CD-R" /*7*/, "CD-ROM" /*8*/, "CD-RW" /*9*/, + "DDCD-R" /*10*/, "DDCD-ROM" /*11*/, "DDCD-RW" /*12*/, "DVD+MRW" /*13*/, + "DVD-R" /*14*/, "DVD+R" /*15*/, "DVD-R DL" /*16*/, "DVD+R DL" /*17*/, + "DVD-RAM" /*18*/, "DVD-ROM" /*19*/, "DVD-RW" /*20*/, "DVD+RW" /*21*/, + "HD DVD-R" /*22*/, "HD DVD-RAM" /*23*/, "HD DVD-ROM" /*24*/, "HD DVD-RW" /*25*/}; + const int mediaKnownArray[] = { audio_cd, bd_r, bd_re, bd_r_lth, bd_r_xl, bd_rom, cd_mrw, cd_r, cd_rom, cd_rw, ddcd_r, ddcd_rom, + ddcd_rw, dvd_p_mrw, dvd_r, dvd_p_r, dvd_r_dl, dvd_p_r_dl, dvd_ram, dvd_rom, dvd_rw, dvd_p_rw, hd_dvd_r, + hd_dvd_ram, hd_dvd_rom, hd_dvd_rw}; + + xmlTextWriterStartElement(xmlWriter, BAD_CAST "TestedMedia"); // + + for(i = 0; i < sizeof(mediaKnownArray) / sizeof(int); i++) + { + if(!mediaKnownArray[i]) + continue; + + user_response = ' '; + do + { + printf("Do you have a %s disc that you can insert in the drive? (Y/N): ", mediaNamesArray[i]); + scanf("%c", &user_response); + printf("\n"); + } while(user_response != 'Y' && user_response != 'y' && user_response != 'N' && user_response != 'n'); + + if(user_response == 'N' || user_response == 'n') + continue; + + AllowMediumRemoval(fd, &buffer); + EjectTray(fd, &buffer); + printf("Please insert it in the drive and press any key when it is ready"); + scanf("%c"); + + error = TestUnitReady(fd, &sense); + int mediaRecognized = TRUE; + int leftRetries = 20; + + xmlTextWriterStartElement(xmlWriter, BAD_CAST "testedMediaType"); // + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "MediumTypeName", "%s", mediaNamesArray[i]); + + if(error) + { + if((sense[0] == 0x70 || sense[0] == 0x71) && (sense[2] & 0x0F) != 0x00) + { + if(sense[12] == 0x3A || sense[12] == 0x28 || (sense[12] == 0x04 && sense[13] == 0x01)) + { + while(leftRetries > 0) + { + printf("\rWating for drive to become ready"); + sleep(2); + error = TestUnitReady(fd, &sense); + if(!error) + break; + + leftRetries--; + } + + printf("\n"); + mediaRecognized = !error; + } + else + mediaRecognized = FALSE; + } + else + mediaRecognized = FALSE; + } + + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "MediaIsRecognized", "%s", mediaRecognized ? "true" : "false"); + + if(!mediaRecognized) + { + xmlTextWriterEndElement(xmlWriter); // + continue; + } + + uint64_t blocks = 0; + uint32_t blockSize = 0; + + printf("Querying SCSI READ CAPACITY...\n"); + error = ReadCapacity(fd, &buffer, &sense, FALSE, 0, FALSE); + if(!error) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsReadCapacity", "%s", "true"); + blocks = (uint64_t)(buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + (buffer[3]) + 1; + blockSize = (uint32_t)((buffer[4] << 24) + (buffer[5] << 16) + (buffer[6] << 8) + (buffer[7])); + } + + printf("Querying SCSI READ CAPACITY (16)...\n"); + error = ReadCapacity16(fd, &buffer, &sense, FALSE, 0); + if(!error) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsReadCapacity16", "%s", "true"); + blocks = (buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + (buffer[3]); + blocks <<= 32; + blocks += (buffer[4] << 24) + (buffer[5] << 16) + (buffer[6] << 8) + (buffer[7]); + blocks++; + blockSize = (uint32_t)((buffer[8] << 24) + (buffer[9] << 16) + (buffer[10] << 8) + (buffer[11])); + } + + if(blocks != 0) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "Blocks", "%llu", blocks); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "BlockSize", "%lu", blockSize); + } + + DecodedMode *decMode; + + printf("Querying SCSI MODE SENSE (10)...\n"); + error = ModeSense10(fd, &buffer, &sense, FALSE, TRUE, MODE_PAGE_DEFAULT, 0x3F, 0x00); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsModeSense10", "%s", !error ? "true" : "false"); + if(!error) + { + xmlTextWriterStartElement(xmlWriter, BAD_CAST "ModeSense10Data"); + xmlTextWriterWriteBase64(xmlWriter, buffer, 0, (*(buffer + 0) << 8) + *(buffer + 1) + 2); + xmlTextWriterEndElement(xmlWriter); + decMode = DecodeMode10(buffer, 0x05); + } + + printf("Querying SCSI MODE SENSE (6)...\n"); + error = ModeSense6(fd, &buffer, &sense, FALSE, MODE_PAGE_DEFAULT, 0x00, 0x00); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsModeSense6", "%s", !error ? "true" : "false"); + if(!error) + { + xmlTextWriterStartElement(xmlWriter, BAD_CAST "ModeSense6Data"); + xmlTextWriterWriteBase64(xmlWriter, buffer, 0, *(buffer + 0) + 1); + xmlTextWriterEndElement(xmlWriter); + if(!decMode->decoded) + decMode = DecodeMode6(buffer, 0x05); + } + + if(decMode->decoded) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "MediumType", "%d", decMode->Header.MediumType); + if(decMode->Header.descriptorsLength > 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "Density", "%d", decMode->Header.BlockDescriptors[0].Density); + } + + // All CDs and DDCDs + if(i == 0 || (i >= 6 && i <= 12)) + { + printf("Querying CD TOC...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadTOC", "%s", !ReadTocPmaAtip(fd, &buffer, &sense, FALSE, 0, 0) ? "true" : "false"); + printf("Querying CD Full TOC...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadFullTOC", "%s", !ReadTocPmaAtip(fd, &buffer, &sense, TRUE, 2, 1) ? "true" : "false"); + } + + // CD-R, CD-RW, CD-MRW, DDCD-R, DDCD-RW + if(i == 6 || i == 7 || i == 9 || i == 10 || i == 12) + { + printf("Querying CD ATIP...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadATIP", "%s", !ReadTocPmaAtip(fd, &buffer, &sense, TRUE, 4, 0) ? "true" : "false"); + printf("Querying CD PMA...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadPMA", "%s", !ReadTocPmaAtip(fd, &buffer, &sense, TRUE, 3, 0) ? "true" : "false"); + } + + // All DVDs and HD DVDs + if(i >= 13 && i <= 25) + { + printf("Querying DVD PFI...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadPFI", "%s", !ReadDiscStructure(fd, &buffer, &sense, DISC_STRUCTURE_DVD, 0, 0, DISC_STRUCTURE_PhysicalInformation, 0) ? "true" : "false"); + printf("Querying DVD DMI...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadDMI", "%s", !ReadDiscStructure(fd, &buffer, &sense, DISC_STRUCTURE_DVD, 0, 0, DISC_STRUCTURE_DiscManufacturingInformation, 0) ? "true" : "false"); + } + + // DVD-ROM + if(i == 19) + { + printf("Querying DVD CMI...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadCMI", "%s", !ReadDiscStructure(fd, &buffer, &sense, DISC_STRUCTURE_DVD, 0, 0, DISC_STRUCTURE_CopyrightInformation, 0) ? "true" : "false"); + } + + // DVD-ROM and HD DVD-ROM + if(i == 19 || i == 23) + { + printf("Querying DVD BCA...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadBCA", "%s", !ReadDiscStructure(fd, &buffer, &sense, DISC_STRUCTURE_DVD, 0, 0, DISC_STRUCTURE_BurstCuttingArea, 0) ? "true" : "false"); + printf("Querying DVD AACS...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadAACS", "%s", !ReadDiscStructure(fd, &buffer, &sense, DISC_STRUCTURE_DVD, 0, 0, DISC_STRUCTURE_DVD_AACS, 0) ? "true" : "false"); + } + + // BD-ROM + if(i == 5) + { + printf("Querying BD BCA...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadBCA", "%s", !ReadDiscStructure(fd, &buffer, &sense, DISC_STRUCTURE_BD, 0, 0, DISC_STRUCTURE_BD_BurstCuttingArea, 0) ? "true" : "false"); + } + + // DVD-RAM and HD DVD-RAM + if(i == 18 || i == 23) + { + printf("Querying DVD DDS...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadDDS", "%s", !ReadDiscStructure(fd, &buffer, &sense, DISC_STRUCTURE_DVD, 0, 0, DISC_STRUCTURE_DVDRAM_DDS, 0) ? "true" : "false"); + printf("Querying DVD SAI...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadSpareAreaInformation", "%s", !ReadDiscStructure(fd, &buffer, &sense, DISC_STRUCTURE_DVD, 0, 0, DISC_STRUCTURE_DVDRAM_SpareAreaInformation, 0) ? "true" : "false"); + } + + // All BDs but BD-ROM + if(i >= 1 || i <= 4) + { + printf("Querying BD DDS...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadDDS", "%s", !ReadDiscStructure(fd, &buffer, &sense, DISC_STRUCTURE_BD, 0, 0, DISC_STRUCTURE_BD_DDS, 0) ? "true" : "false"); + printf("Querying BD SAI...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadSpareAreaInformation", "%s", !ReadDiscStructure(fd, &buffer, &sense, DISC_STRUCTURE_BD, 0, 0, DISC_STRUCTURE_BD_SpareAreaInformation, 0) ? "true" : "false"); + } + + // DVD-R and DVD-RW + if(i == 14 || i == 20) + { + printf("Querying DVD PRI...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadPRI", "%s", !ReadDiscStructure(fd, &buffer, &sense, DISC_STRUCTURE_DVD, 0, 0, DISC_STRUCTURE_PreRecordedInfo, 0) ? "true" : "false"); + } + + // DVD-R, DVD-RW and HD DVD-R + if(i == 14 || i == 20 || i == 22) + { + printf("Querying DVD Media ID...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadMediaID", "%s", !ReadDiscStructure(fd, &buffer, &sense, DISC_STRUCTURE_DVD, 0, 0, DISC_STRUCTURE_DVDR_MediaIdentifier, 0) ? "true" : "false"); + printf("Querying DVD Embossed PFI...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadRecordablePFI", "%s", !ReadDiscStructure(fd, &buffer, &sense, DISC_STRUCTURE_DVD, 0, 0, DISC_STRUCTURE_DVDR_PhysicalInformation, 0) ? "true" : "false"); + } + + // All DVD+Rs + if(i == 13 || i == 15 || i == 17 || i == 21) + { + printf("Querying DVD ADIP...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadADIP", "%s", !ReadDiscStructure(fd, &buffer, &sense, DISC_STRUCTURE_DVD, 0, 0, DISC_STRUCTURE_ADIP, 0) ? "true" : "false"); + printf("Querying DVD DCB...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadDCB", "%s", !ReadDiscStructure(fd, &buffer, &sense, DISC_STRUCTURE_DVD, 0, 0, DISC_STRUCTURE_DCB, 0) ? "true" : "false"); + } + + // HD DVD-ROM + if(i == 24) + { + printf("Querying HD DVD CMI...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadHDCMI", "%s", !ReadDiscStructure(fd, &buffer, &sense, DISC_STRUCTURE_DVD, 0, 0, DISC_STRUCTURE_HDDVD_CopyrightInformation, 0) ? "true" : "false"); + } + + // All dual-layer + if(i == 16 || i == 17) + { + printf("Querying HD DVD CMI...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadLayerCapacity", "%s", !ReadDiscStructure(fd, &buffer, &sense, DISC_STRUCTURE_DVD, 0, 0, DISC_STRUCTURE_DVDR_LayerCapacity, 0) ? "true" : "false"); + } + + // All BDs + if(i >= 16 && i <= 5) + { + printf("Querying BD Disc Information...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadDiscInformation", "%s", !ReadDiscStructure(fd, &buffer, &sense, DISC_STRUCTURE_BD, 0, 0, DISC_STRUCTURE_DiscInformation, 0) ? "true" : "false"); + printf("Querying BD PAC...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadPAC", "%s", !ReadDiscStructure(fd, &buffer, &sense, DISC_STRUCTURE_BD, 0, 0, DISC_STRUCTURE_PAC, 0) ? "true" : "false"); + } + + printf("Trying SCSI READ (6)...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsRead", "%s", !Read6(fd, &buffer, &sense, 0, blockSize, 1) ? "true" : "false"); + + printf("Trying SCSI READ (10)...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsRead10", "%s", !Read10(fd, &buffer, &sense, 0, FALSE, TRUE, FALSE, FALSE, 0, blockSize, 0, 1) ? "true" : "false"); + + printf("Trying SCSI READ (12)...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsRead12", "%s", !Read12(fd, &buffer, &sense, 0, FALSE, TRUE, FALSE, FALSE, 0, blockSize, 0, 1, FALSE) ? "true" : "false"); + + printf("Trying SCSI READ (16)...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsRead16", "%s", !Read16(fd, &buffer, &sense, 0, FALSE, TRUE, FALSE, 0, blockSize, 0, 1, FALSE) ? "true" : "false"); + + if(!tryHLDTST) + { + user_response = ' '; + do + { + printf("Do you have want to try HL-DT-ST (aka LG) vendor commands? THIS IS DANGEROUS AND CAN IRREVERSIBLY DESTROY YOUR DRIVE (IF IN DOUBT PRESS 'N') (Y/N): "); + scanf("%c", &user_response); + printf("\n"); + } while(user_response != 'Y' && user_response != 'y' && user_response != 'N' && user_response != 'n'); + + tryNEC = user_response == 'Y' || user_response == 'y'; + } + + if(!tryHLDTST) + { + user_response = ' '; + do + { + printf("Do you have want to try NEC vendor commands? THIS IS DANGEROUS AND CAN IRREVERSIBLY DESTROY YOUR DRIVE (IF IN DOUBT PRESS 'N') (Y/N): "); + scanf("%c", &user_response); + printf("\n"); + } while(user_response != 'Y' && user_response != 'y' && user_response != 'N' && user_response != 'n'); + + tryNEC = user_response == 'Y' || user_response == 'y'; + } + + if(!tryPlextor) + { + user_response = ' '; + do + { + printf("Do you have want to try Plextor vendor commands? THIS IS DANGEROUS AND CAN IRREVERSIBLY DESTROY YOUR DRIVE (IF IN DOUBT PRESS 'N') (Y/N): "); + scanf("%c", &user_response); + printf("\n"); + } while(user_response != 'Y' && user_response != 'y' && user_response != 'N' && user_response != 'n'); + + tryPlextor = user_response == 'Y' || user_response == 'y'; + } + + if(!tryPioneer) + { + user_response = ' '; + do + { + printf("Do you have want to try Pioneer vendor commands? THIS IS DANGEROUS AND CAN IRREVERSIBLY DESTROY YOUR DRIVE (IF IN DOUBT PRESS 'N') (Y/N): "); + scanf("%c", &user_response); + printf("\n"); + } while(user_response != 'Y' && user_response != 'y' && user_response != 'N' && user_response != 'n'); + + tryPioneer = user_response == 'Y' || user_response == 'y'; + } + + // All CDs and DDCDs + if(i == 0 || (i >= 6 && i <= 12)) + { + int supportsReadCdRaw = FALSE; + int j; + + // Audio CD + if(i == 0) + { + printf("Trying SCSI READ CD...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsReadCd", "%s", !ReadCd(fd, &buffer, &sense, 0, 2352, 1, MMC_SECTOR_CDDA, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_NONE, MMC_SUBCHANNEL_NONE) ? "true" : "false"); + printf("Trying SCSI READ CD MSF...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsReadCdMsf", "%s", !ReadCdMsf(fd, &buffer, &sense, 0x00000200, 0x00000201, 2352, MMC_SECTOR_CDDA, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_NONE, MMC_SUBCHANNEL_NONE) ? "true" : "false"); + } + else + { + printf("Trying SCSI READ CD...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsReadCd", "%s", !ReadCd(fd, &buffer, &sense, 0, 2048, 1, MMC_SECTOR_ALL, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_NONE, MMC_SUBCHANNEL_NONE) ? "true" : "false"); + printf("Trying SCSI READ CD MSF...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsReadCdMsf", "%s", !ReadCdMsf(fd, &buffer, &sense, 0x00000200, 0x00000201, 2048, MMC_SECTOR_ALL, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_NONE, MMC_SUBCHANNEL_NONE) ? "true" : "false"); + printf("Trying SCSI READ CD full sector...\n"); + supportsReadCdRaw = !ReadCd(fd, &buffer, &sense, 0, 2352, 1, MMC_SECTOR_ALL, FALSE, FALSE, TRUE, MMC_HEADER_ALL, TRUE, TRUE, MMC_ERROR_NONE, MMC_SUBCHANNEL_NONE); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsReadCdRaw", "%s", supportsReadCdRaw ? "true" : "false"); + printf("Trying SCSI READ CD MSF full sector...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsReadCdMsfRaw", "%s", !ReadCdMsf(fd, &buffer, &sense, 0x00000200, 0x00000201, 2352, MMC_SECTOR_ALL, FALSE, FALSE, MMC_HEADER_ALL, TRUE, TRUE, MMC_ERROR_NONE, MMC_SUBCHANNEL_NONE) ? "true" : "false"); + } + + if(supportsReadCdRaw || i == 0) + { + printf("Trying to read CD Lead-In...\n"); + + for(j = -150; j < 0; j++) + { + if(i == 0) + error = ReadCd(fd, &buffer, &sense, (uint32_t)i, 2352, 1, MMC_SECTOR_CDDA, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_NONE, MMC_SUBCHANNEL_NONE); + else + error = ReadCd(fd, &buffer, &sense, (uint32_t)i, 2352, 1, MMC_SECTOR_ALL, FALSE, FALSE, TRUE, MMC_HEADER_ALL, TRUE, TRUE, MMC_ERROR_NONE, MMC_SUBCHANNEL_NONE); + + if(!error) + break; + } + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadLeadIn", "%s", !error ? "true" : "false"); + + printf("Trying to read CD Lead-Out...\n"); + if(i == 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadLeadOut", "%s", !ReadCd(fd, &buffer, &sense, (uint)(blocks + 1), 2352, 1, MMC_SECTOR_CDDA, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_NONE, MMC_SUBCHANNEL_NONE) ? "true" : "false"); + else + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadLeadOut", "%s", !ReadCd(fd, &buffer, &sense, (uint)(blocks + 1), 2352, 1, MMC_SECTOR_ALL, FALSE, FALSE, TRUE, MMC_HEADER_ALL, TRUE, TRUE, MMC_ERROR_NONE, MMC_SUBCHANNEL_NONE) ? "true" : "false"); + } + + // Audio CD + if(i == 0) + { + printf("Trying to read C2 Pointers...\n"); + error = ReadCd(fd, &buffer, &sense, 0, 2646, 1, MMC_SECTOR_CDDA, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_C2, MMC_SUBCHANNEL_NONE); + if(error) + error = ReadCd(fd, &buffer, &sense, 0, 2648, 1, MMC_SECTOR_CDDA, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_C2_AND_BLOCK, MMC_SUBCHANNEL_NONE); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadC2Pointers", "%s", !error ? "true" : "false"); + + printf("Trying to read subchannels...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadPQSubchannel", "%s", !ReadCd(fd, &buffer, &sense, 0, 2368, 1, MMC_SECTOR_CDDA, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_NONE, MMC_SUBCHANNEL_Q16) ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadRWSubchannel", "%s", !ReadCd(fd, &buffer, &sense, 0, 2448, 1, MMC_SECTOR_CDDA, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_NONE, MMC_SUBCHANNEL_RAW) ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadCorrectedSubchannel", "%s", !ReadCd(fd, &buffer, &sense, 0, 2448, 1, MMC_SECTOR_CDDA, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_NONE, MMC_SUBCHANNEL_RW) ? "true" : "false"); + + printf("Trying to read subchannels with C2 Pointers...\n"); + error = ReadCd(fd, &buffer, &sense, 0, 2662, 1, MMC_SECTOR_CDDA, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_C2, MMC_SUBCHANNEL_Q16); + if(error) + error = ReadCd(fd, &buffer, &sense, 0, 2664, 1, MMC_SECTOR_CDDA, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_C2_AND_BLOCK, MMC_SUBCHANNEL_Q16); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadPQSubchannelWithC2", "%s", !error ? "true" : "false"); + + error = ReadCd(fd, &buffer, &sense, 0, 2712, 1, MMC_SECTOR_CDDA, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_C2, MMC_SUBCHANNEL_RAW); + if(error) + error = ReadCd(fd, &buffer, &sense, 0, 2714, 1, MMC_SECTOR_CDDA, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_C2_AND_BLOCK, MMC_SUBCHANNEL_RAW); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadRWSubchannelWithC2", "%s", !error ? "true" : "false"); + + error = ReadCd(fd, &buffer, &sense, 0, 2712, 1, MMC_SECTOR_CDDA, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_C2, MMC_SUBCHANNEL_RW); + if(error) + error = ReadCd(fd, &buffer, &sense, 0, 2714, 1, MMC_SECTOR_CDDA, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_C2_AND_BLOCK, MMC_SUBCHANNEL_RW); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadCorrectedSubchannelWithC2", "%s", !error ? "true" : "false"); + } + else if(supportsReadCdRaw) + { + printf("Trying to read C2 Pointers...\n"); + error = ReadCd(fd, &buffer, &sense, 0, 2646, 1, MMC_SECTOR_ALL, FALSE, FALSE, TRUE, MMC_HEADER_ALL, TRUE, TRUE, MMC_ERROR_C2, MMC_SUBCHANNEL_NONE); + if(error) + error = ReadCd(fd, &buffer, &sense, 0, 2648, 1, MMC_SECTOR_ALL, FALSE, FALSE, TRUE, MMC_HEADER_ALL, TRUE, TRUE, MMC_ERROR_C2_AND_BLOCK, MMC_SUBCHANNEL_NONE); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadC2Pointers", "%s", !error ? "true" : "false"); + + printf("Trying to read subchannels...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadPQSubchannel", "%s", !ReadCd(fd, &buffer, &sense, 0, 2368, 1, MMC_SECTOR_ALL, FALSE, FALSE, TRUE, MMC_HEADER_ALL, TRUE, TRUE, MMC_ERROR_NONE, MMC_SUBCHANNEL_Q16) ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadRWSubchannel", "%s", !ReadCd(fd, &buffer, &sense, 0, 2448, 1, MMC_SECTOR_ALL, FALSE, FALSE, TRUE, MMC_HEADER_ALL, TRUE, TRUE, MMC_ERROR_NONE, MMC_SUBCHANNEL_RAW) ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadCorrectedSubchannel", "%s", !ReadCd(fd, &buffer, &sense, 0, 2448, 1, MMC_SECTOR_ALL, FALSE, FALSE, TRUE, MMC_HEADER_ALL, TRUE, TRUE, MMC_ERROR_NONE, MMC_SUBCHANNEL_RW) ? "true" : "false"); + + printf("Trying to read subchannels with C2 Pointers...\n"); + error = ReadCd(fd, &buffer, &sense, 0, 2662, 1, MMC_SECTOR_ALL, FALSE, FALSE, TRUE, MMC_HEADER_ALL, TRUE, TRUE, MMC_ERROR_C2, MMC_SUBCHANNEL_Q16); + if(error) + error = ReadCd(fd, &buffer, &sense, 0, 2664, 1, MMC_SECTOR_ALL, FALSE, FALSE, TRUE, MMC_HEADER_ALL, TRUE, TRUE, MMC_ERROR_C2_AND_BLOCK, MMC_SUBCHANNEL_Q16); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadPQSubchannelWithC2", "%s", !error ? "true" : "false"); + + error = ReadCd(fd, &buffer, &sense, 0, 2712, 1, MMC_SECTOR_ALL, FALSE, FALSE, TRUE, MMC_HEADER_ALL, TRUE, TRUE, MMC_ERROR_C2, MMC_SUBCHANNEL_RAW); + if(error) + error = ReadCd(fd, &buffer, &sense, 0, 2714, 1, MMC_SECTOR_ALL, FALSE, FALSE, TRUE, MMC_HEADER_ALL, TRUE, TRUE, MMC_ERROR_C2_AND_BLOCK, MMC_SUBCHANNEL_RAW); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadRWSubchannelWithC2", "%s", !error ? "true" : "false"); + + error = ReadCd(fd, &buffer, &sense, 0, 2712, 1, MMC_SECTOR_ALL, FALSE, FALSE, TRUE, MMC_HEADER_ALL, TRUE, TRUE, MMC_ERROR_C2, MMC_SUBCHANNEL_RW); + if(error) + error = ReadCd(fd, &buffer, &sense, 0, 2714, 1, MMC_SECTOR_ALL, FALSE, FALSE, TRUE, MMC_HEADER_ALL, TRUE, TRUE, MMC_ERROR_C2_AND_BLOCK, MMC_SUBCHANNEL_RW); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadCorrectedSubchannelWithC2", "%s", !error ? "true" : "false"); + } + else + { + printf("Trying to read C2 Pointers...\n"); + error = ReadCd(fd, &buffer, &sense, 0, 2342, 1, MMC_SECTOR_ALL, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_C2, MMC_SUBCHANNEL_NONE); + if(error) + error = ReadCd(fd, &buffer, &sense, 0, 2344, 1, MMC_SECTOR_ALL, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_C2_AND_BLOCK, MMC_SUBCHANNEL_NONE); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadC2Pointers", "%s", !error ? "true" : "false"); + + printf("Trying to read subchannels...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadPQSubchannel", "%s", !ReadCd(fd, &buffer, &sense, 0, 2064, 1, MMC_SECTOR_ALL, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_NONE, MMC_SUBCHANNEL_Q16) ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadRWSubchannel", "%s", !ReadCd(fd, &buffer, &sense, 0, 2144, 1, MMC_SECTOR_ALL, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_NONE, MMC_SUBCHANNEL_RAW) ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadCorrectedSubchannel", "%s", !ReadCd(fd, &buffer, &sense, 0, 2144, 1, MMC_SECTOR_ALL, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_NONE, MMC_SUBCHANNEL_RW) ? "true" : "false"); + + printf("Trying to read subchannels with C2 Pointers...\n"); + error = ReadCd(fd, &buffer, &sense, 0, 2358, 1, MMC_SECTOR_ALL, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_C2, MMC_SUBCHANNEL_Q16); + if(error) + error = ReadCd(fd, &buffer, &sense, 0, 2360, 1, MMC_SECTOR_ALL, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_C2_AND_BLOCK, MMC_SUBCHANNEL_Q16); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadC2Pointers", "%s", !error ? "true" : "false"); + + error = ReadCd(fd, &buffer, &sense, 0, 2438, 1, MMC_SECTOR_ALL, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_C2, MMC_SUBCHANNEL_RAW); + if(error) + error = ReadCd(fd, &buffer, &sense, 0, 2440, 1, MMC_SECTOR_ALL, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_C2_AND_BLOCK, MMC_SUBCHANNEL_RAW); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadC2Pointers", "%s", !error ? "true" : "false"); + + error = ReadCd(fd, &buffer, &sense, 0, 2438, 1, MMC_SECTOR_ALL, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_C2, MMC_SUBCHANNEL_RW); + if(error) + error = ReadCd(fd, &buffer, &sense, 0, 2440, 1, MMC_SECTOR_ALL, FALSE, FALSE, FALSE, MMC_HEADER_NONE, TRUE, FALSE, MMC_ERROR_C2_AND_BLOCK, MMC_SUBCHANNEL_RW); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "CanReadC2Pointers", "%s", !error ? "true" : "false"); + } + + if(tryPlextor) + { + printf("Trying Plextor READ CD-DA...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsPlextorReadCDDA", "%s", !PlextorReadCdDa(fd, &buffer, &sense, 0, 2352, 1, PLEXTOR_SUBCHANNEL_NONE) ? "true" : "false"); + } + + if(tryPioneer) + { + printf("Trying Pioneer READ CD-DA...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsPioneerReadCDDA", "%s", !PioneerReadCdDa(fd, &buffer, &sense, 0, 2352, 1, PIONEER_SUBCHANNEL_NONE) ? "true" : "false"); + printf("Trying Pioneer READ CD-DA MSF...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsPioneerReadCDDAMSF", "%s", !PioneerReadCdDaMsf(fd, &buffer, &sense, 0x00000200, 0x00000201, 2352, PIONEER_SUBCHANNEL_NONE) ? "true" : "false"); + } + + if(tryNEC) + { + printf("Trying NEC READ CD-DA...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsNECReadCDDA", "%s", !NecReadCdDa(fd, &buffer, &sense, 0, 1) ? "true" : "false"); + } + + }// All CDs and DDCDs + + if(tryPlextor) + { + printf("Trying Plextor trick to raw read DVDs...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsPlextorReadRawDVD", "%s", !PlextorReadRawDvd(fd, &buffer, &sense, 0, 1) ? "true" : "false"); +// if(mediaTest.SupportsPlextorReadRawDVD) +// mediaTest.SupportsPlextorReadRawDVD = !ArrayHelpers.ArrayIsNullOrEmpty(buffer); + } + + if(tryHLDTST) + { + printf("Trying HL-DT-ST (aka LG) trick to raw read DVDs...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsHLDTSTReadRawDVD", "%s", !HlDtStReadRawDvd(fd, &buffer, &sense, 0, 1) ? "true" : "false"); + } + + uint32_t longBlockSize = blockSize; + + int supportsReadLong10 = FALSE; + + printf("Trying SCSI READ LONG (10)...\n"); + ReadLong10(fd, &buffer, &sense, FALSE, FALSE, 0, 0xFFFF); + if((sense[0] == 0x70 || sense[0] == 0x71) && (sense[2] & 0x0F) == 0x05 && sense[12] == 0x24 && sense[13] == 0x00) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsReadLong", "%s", "true"); + supportsReadLong10 = TRUE; + if(sense[0] & 0x80 && sense[2] & 0x20) + { + uint32_t information = (sense[3] << 24) + (sense[4] << 16) + (sense[5] << 8) + sense[6]; + longBlockSize = 0xFFFF - (information & 0xFFFF); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "LongBlockSize", "%d", longBlockSize); + } + } + + printf("Trying SCSI READ LONG (16)...\n"); + ReadLong16(fd, &buffer, &sense, FALSE, 0, 0xFFFF); + if((sense[0] == 0x70 || sense[0] == 0x71) && (sense[2] & 0x0F) == 0x05 && sense[12] == 0x24 && sense[13] == 0x00) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsReadLong16", "%s", "true"); + + int i; + + if(supportsReadLong10 && blockSize == longBlockSize) + { + error = ReadLong10(fd, &buffer, &sense, FALSE, FALSE, 0, 37856); + if(!error) + { + longBlockSize = 37856; + break; + } + } + + if(supportsReadLong10 && blockSize == longBlockSize) + { + user_response = ' '; + do + { + printf("Drive supports SCSI READ LONG but I cannot find the correct size. Do you want me to try? (This can take hours) (Y/N): "); + scanf("%c", &user_response); + printf("\n"); + } while(user_response != 'Y' && user_response != 'y' && user_response != 'N' && user_response != 'n'); + + if(user_response == 'Y' || user_response == 'y') + { + uint j; + for(j = blockSize; j <= 65536; j++) + { + printf("\rTrying to READ LONG with a size of %d bytes", j); + error = ReadLong10(fd, &buffer, &sense, FALSE, FALSE, 0, j); + if(!error) + { + longBlockSize = j; + break; + } + } + printf("\n"); + } + + user_response = ' '; + } + + if(supportsReadLong10 && blockSize != longBlockSize) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "LongBlockSize", "%d", longBlockSize); + + xmlTextWriterEndElement(xmlWriter); // + } + + xmlTextWriterEndElement(xmlWriter); // + xmlTextWriterEndElement(xmlWriter); // +} + +SeparatedFeatures Separate(unsigned char* response) +{ + SeparatedFeatures dec; + memset(&dec, 0, sizeof(SeparatedFeatures)); + dec.DataLength = (uint32_t)((response[0] << 24) + (response[1] << 16) + (response[2] << 8) + response[3]); + dec.CurrentProfile = (uint16_t)((response[6] << 8) + response[7]); + int offset = 8; + + while((offset + 4) < dec.DataLength) + { + uint16_t code = (uint16_t)((response[offset + 0] << 8) + response[offset + 1]); + dec.Descriptors[code].len = response[offset + 3] + 4; + dec.Descriptors[code].data = malloc(dec.Descriptors[code].len); + memset(dec.Descriptors[code].data, 0, dec.Descriptors[code].len); + memcpy(dec.Descriptors[code].data, response + offset, dec.Descriptors[code].len); + dec.Descriptors[code].present = TRUE; + offset += dec.Descriptors[code].len; + } + + if(dec.Descriptors[0].present) + { + offset = 4; + while((offset + 4) < dec.Descriptors[0].len) + { + uint16_t code = (uint16_t)((dec.Descriptors[0].data[offset + 0] << 8) + dec.Descriptors[0].data[offset + 1]); + dec.Descriptors[code].present = TRUE; + offset+=4; + } + } + + return dec; +} \ No newline at end of file diff --git a/DiscImageChef.Device.Report/mmc_report.h b/DiscImageChef.Device.Report/mmc_report.h new file mode 100644 index 000000000..fac20bdfd --- /dev/null +++ b/DiscImageChef.Device.Report/mmc_report.h @@ -0,0 +1,23 @@ +// +// Created by claunia on 17/12/17. +// + +#ifndef DISCIMAGECHEF_DEVICE_REPORT_MMC_REPORT_H +#define DISCIMAGECHEF_DEVICE_REPORT_MMC_REPORT_H + +void MmcReport(int fd, xmlTextWriterPtr xmlWriter, unsigned char* cdromMode); + +typedef struct +{ + int present; + size_t len; + unsigned char* data; +} FeatureDescriptors; + +typedef struct +{ + uint32_t DataLength; + uint16_t CurrentProfile; + FeatureDescriptors Descriptors[65536]; +} SeparatedFeatures; +#endif //DISCIMAGECHEF_DEVICE_REPORT_MMC_REPORT_H diff --git a/DiscImageChef.Device.Report/scsi.c b/DiscImageChef.Device.Report/scsi.c index a5df20ed0..f7e6097a0 100644 --- a/DiscImageChef.Device.Report/scsi.c +++ b/DiscImageChef.Device.Report/scsi.c @@ -539,3 +539,311 @@ int TestUnitReady(int fd, unsigned char **senseBuffer) return error; } + +int GetConfiguration(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint16_t startingFeatureNumber, uint8_t RT) +{ + unsigned char cmd_len = 10; + uint16_t buffer_len = 8; + *buffer = malloc(buffer_len); + memset(*buffer, 0, buffer_len); + char cdb[] = {MMC_GET_CONFIGURATION, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + cdb[1] = (uint8_t)(RT & 0x03); + cdb[2] = (uint8_t)((startingFeatureNumber & 0xFF00) >> 8); + cdb[3] = (uint8_t)(startingFeatureNumber & 0xFF); + cdb[7] = (uint8_t)((buffer_len & 0xFF00) >> 8); + cdb[8] = (uint8_t)(buffer_len & 0xFF); + cdb[9] = 0; + + int error = SendScsiCommand(fd, &cdb, cmd_len, *buffer, buffer_len, senseBuffer, SG_DXFER_FROM_DEV); + + if(error) + return error; + + buffer_len = (uint16_t)(*(*buffer + 2) << 8) + *(*buffer + 3) + 2; + cdb[7] = (uint8_t)((buffer_len & 0xFF00) >> 8); + cdb[8] = (uint8_t)(buffer_len & 0xFF); + + free(*buffer); + *buffer = malloc(buffer_len); + memset(*buffer, 0, buffer_len); + + error = SendScsiCommand(fd, &cdb, cmd_len, *buffer, buffer_len, senseBuffer, SG_DXFER_FROM_DEV); + + return error; +} + +int ReadTocPmaAtip(int fd, unsigned char **buffer, unsigned char **senseBuffer, int MSF, uint8_t format, uint8_t trackSessionNumber) +{ + unsigned char cmd_len = 10; + uint16_t buffer_len = 1024; + char cdb[] = {MMC_READ_TOC_PMA_ATIP, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + if((format & 0xF) == 5) + buffer_len = 32768; + + *buffer = malloc(buffer_len); + memset(*buffer, 0, buffer_len); + + if(MSF) + cdb[1] = 0x02; + cdb[2] = (uint8_t)(format & 0x0F); + cdb[6] = trackSessionNumber; + cdb[7] = (uint8_t)((buffer_len & 0xFF00) >> 8); + cdb[8] = (uint8_t)(buffer_len & 0xFF); + + int error = SendScsiCommand(fd, &cdb, cmd_len, *buffer, buffer_len, senseBuffer, SG_DXFER_FROM_DEV); + + if(error) + return error; + + buffer_len = (uint16_t)(*(*buffer + 0) << 8) + *(*buffer + 1) + 2; + cdb[7] = (uint8_t)((buffer_len & 0xFF00) >> 8); + cdb[8] = (uint8_t)(buffer_len & 0xFF); + + free(*buffer); + *buffer = malloc(buffer_len); + memset(*buffer, 0, buffer_len); + + error = SendScsiCommand(fd, &cdb, cmd_len, *buffer, buffer_len, senseBuffer, SG_DXFER_FROM_DEV); + + return error; +} + +int ReadDiscStructure(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint8_t mediaType, uint32_t address, uint8_t layerNumber, uint8_t format, uint8_t AGID) +{ + unsigned char cmd_len = 12; + uint16_t buffer_len = 8; + *buffer = malloc(buffer_len); + memset(*buffer, 0, buffer_len); + char cdb[] = {MMC_READ_DISC_STRUCTURE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + cdb[1] = (uint8_t)((uint8_t)mediaType & 0x0F); + cdb[2] = (uint8_t)((address & 0xFF000000) >> 24); + cdb[3] = (uint8_t)((address & 0xFF0000) >> 16); + cdb[4] = (uint8_t)((address & 0xFF00) >> 8); + cdb[5] = (uint8_t)(address & 0xFF); + cdb[6] = layerNumber; + cdb[7] = (uint8_t)format; + cdb[8] = (uint8_t)((buffer_len & 0xFF00) >> 8); + cdb[9] = (uint8_t)(buffer_len & 0xFF); + cdb[10] = (uint8_t)((AGID & 0x03) << 6); + + int error = SendScsiCommand(fd, &cdb, cmd_len, *buffer, buffer_len, senseBuffer, SG_DXFER_FROM_DEV); + + if(error) + return error; + + buffer_len = (uint16_t)(*(*buffer + 0) << 8) + *(*buffer + 1) + 2; + cdb[8] = (uint8_t)((buffer_len & 0xFF00) >> 8); + cdb[9] = (uint8_t)(buffer_len & 0xFF); + + free(*buffer); + *buffer = malloc(buffer_len); + memset(*buffer, 0, buffer_len); + + error = SendScsiCommand(fd, &cdb, cmd_len, *buffer, buffer_len, senseBuffer, SG_DXFER_FROM_DEV); + + return error; +} + +int ReadCd(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint32_t lba, uint32_t blockSize, uint32_t transferLength, uint8_t expectedSectorType, +int DAP, int relAddr, int sync, uint8_t headerCodes, int userData, int edcEcc, uint8_t C2Error, uint8_t subchannel) +{ + unsigned char cmd_len = 12; + uint32_t buffer_len = transferLength * blockSize; + *buffer = malloc(buffer_len); + memset(*buffer, 0, buffer_len); + char cdb[] = {MMC_READ_CD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + cdb[1] = (uint8_t)((uint8_t)expectedSectorType << 2); + if(DAP) + cdb[1] += 0x02; + if(relAddr) + cdb[1] += 0x01; + cdb[2] = (uint8_t)((lba & 0xFF000000) >> 24); + cdb[3] = (uint8_t)((lba & 0xFF0000) >> 16); + cdb[4] = (uint8_t)((lba & 0xFF00) >> 8); + cdb[5] = (uint8_t)(lba & 0xFF); + cdb[6] = (uint8_t)((transferLength & 0xFF0000) >> 16); + cdb[7] = (uint8_t)((transferLength & 0xFF00) >> 8); + cdb[8] = (uint8_t)(transferLength & 0xFF); + cdb[9] = (uint8_t)((uint8_t)C2Error << 1); + cdb[9] += (uint8_t)((uint8_t)headerCodes << 5); + if(sync) + cdb[9] += 0x80; + if(userData) + cdb[9] += 0x10; + if(edcEcc) + cdb[9] += 0x08; + cdb[10] = (uint8_t)subchannel; + + int error = SendScsiCommand(fd, &cdb, cmd_len, *buffer, buffer_len, senseBuffer, SG_DXFER_FROM_DEV); + + return error; +} + +int ReadCdMsf(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint32_t startMsf, uint32_t endMsf, uint32_t blockSize, uint8_t expectedSectorType, +int DAP, int sync, uint8_t headerCodes, int userData, int edcEcc, uint8_t C2Error, uint8_t subchannel) +{ + unsigned char cmd_len = 12; + char cdb[] = {MMC_READ_CD_MSF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + cdb[1] = (uint8_t)((uint8_t)expectedSectorType << 2); + if(DAP) + cdb[1] += 0x02; + cdb[3] = (uint8_t)((startMsf & 0xFF0000) >> 16); + cdb[4] = (uint8_t)((startMsf & 0xFF00) >> 8); + cdb[5] = (uint8_t)(startMsf & 0xFF); + cdb[6] = (uint8_t)((endMsf & 0xFF0000) >> 16); + cdb[7] = (uint8_t)((endMsf & 0xFF00) >> 8); + cdb[8] = (uint8_t)(endMsf & 0xFF); + cdb[9] = (uint8_t)((uint8_t)C2Error << 1); + cdb[9] += (uint8_t)((uint8_t)headerCodes << 5); + if(sync) + cdb[9] += 0x80; + if(userData) + cdb[9] += 0x10; + if(edcEcc) + cdb[9] += 0x08; + cdb[10] = (uint8_t)subchannel; + + uint32_t transferLength = (uint32_t)((cdb[6] - cdb[3]) * 60 * 75 + (cdb[7] - cdb[4]) * 75 + (cdb[8] - cdb[5])); + uint32_t buffer_len = transferLength * blockSize; + *buffer = malloc(buffer_len); + memset(*buffer, 0, buffer_len); + + int error = SendScsiCommand(fd, &cdb, cmd_len, *buffer, buffer_len, senseBuffer, SG_DXFER_FROM_DEV); + + return error; +} + +int PlextorReadCdDa(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint32_t lba, uint32_t blockSize, uint32_t transferLength, uint8_t subchannel) +{ + unsigned char cmd_len = 12; + uint32_t buffer_len = transferLength * blockSize; + *buffer = malloc(buffer_len); + memset(*buffer, 0, buffer_len); + char cdb[] = {PIONEER_READ_CDDA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + cdb[2] = (uint8_t)((lba & 0xFF000000) >> 24); + cdb[3] = (uint8_t)((lba & 0xFF0000) >> 16); + cdb[4] = (uint8_t)((lba & 0xFF00) >> 8); + cdb[5] = (uint8_t)(lba & 0xFF); + cdb[6] = (uint8_t)((transferLength & 0xFF000000) >> 24); + cdb[7] = (uint8_t)((transferLength & 0xFF0000) >> 16); + cdb[8] = (uint8_t)((transferLength & 0xFF00) >> 8); + cdb[9] = (uint8_t)(transferLength & 0xFF); + cdb[10] = (uint8_t)subchannel; + + int error = SendScsiCommand(fd, &cdb, cmd_len, *buffer, buffer_len, senseBuffer, SG_DXFER_FROM_DEV); + + return error; +} + +int PlextorReadRawDvd(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint32_t lba, uint32_t transferLength) +{ + unsigned char cmd_len = 10; + uint32_t buffer_len = transferLength * 2064; + *buffer = malloc(buffer_len); + memset(*buffer, 0, buffer_len); + char cdb[] = {SCSI_READ_BUFFER, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + cdb[1] = 0x02; + cdb[3] = (uint8_t)((lba & 0xFF0000) >> 16); + cdb[4] = (uint8_t)((lba & 0xFF00) >> 8); + cdb[5] = (uint8_t)(lba & 0xFF); + cdb[3] = (uint8_t)((buffer_len & 0xFF0000) >> 16); + cdb[4] = (uint8_t)((buffer_len & 0xFF00) >> 8); + cdb[5] = (uint8_t)(buffer_len & 0xFF); + + int error = SendScsiCommand(fd, &cdb, cmd_len, *buffer, buffer_len, senseBuffer, SG_DXFER_FROM_DEV); + + return error; +} + +int PioneerReadCdDa(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint32_t lba, uint32_t blockSize, uint32_t transferLength, uint8_t subchannel) +{ + unsigned char cmd_len = 12; + uint32_t buffer_len = transferLength * blockSize; + *buffer = malloc(buffer_len); + memset(*buffer, 0, buffer_len); + char cdb[] = {PIONEER_READ_CDDA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + cdb[2] = (uint8_t)((lba & 0xFF000000) >> 24); + cdb[3] = (uint8_t)((lba & 0xFF0000) >> 16); + cdb[4] = (uint8_t)((lba & 0xFF00) >> 8); + cdb[5] = (uint8_t)(lba & 0xFF); + cdb[7] = (uint8_t)((transferLength & 0xFF0000) >> 16); + cdb[8] = (uint8_t)((transferLength & 0xFF00) >> 8); + cdb[9] = (uint8_t)(transferLength & 0xFF); + cdb[10] = (uint8_t)subchannel; + + int error = SendScsiCommand(fd, &cdb, cmd_len, *buffer, buffer_len, senseBuffer, SG_DXFER_FROM_DEV); + + return error; +} + +int PioneerReadCdDaMsf(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint32_t startMsf, uint32_t endMsf, uint32_t blockSize, uint8_t subchannel) +{ + unsigned char cmd_len = 12; + char cdb[] = {PIONEER_READ_CDDA_MSF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + cdb[3] = (uint8_t)((startMsf & 0xFF0000) >> 16); + cdb[4] = (uint8_t)((startMsf & 0xFF00) >> 8); + cdb[5] = (uint8_t)(startMsf & 0xFF); + cdb[7] = (uint8_t)((endMsf & 0xFF0000) >> 16); + cdb[8] = (uint8_t)((endMsf & 0xFF00) >> 8); + cdb[9] = (uint8_t)(endMsf & 0xFF); + cdb[10] = (uint8_t)subchannel; + + uint32_t transferLength = (uint)((cdb[7] - cdb[3]) * 60 * 75 + (cdb[8] - cdb[4]) * 75 + (cdb[9] - cdb[5])); + uint32_t buffer_len = transferLength * blockSize; + *buffer = malloc(buffer_len); + memset(*buffer, 0, buffer_len); + + int error = SendScsiCommand(fd, &cdb, cmd_len, *buffer, buffer_len, senseBuffer, SG_DXFER_FROM_DEV); + + return error; +} + +int NecReadCdDa(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint32_t lba, uint32_t transferLength) +{ + unsigned char cmd_len = 12; + uint32_t buffer_len = transferLength * 2352; + *buffer = malloc(buffer_len); + memset(*buffer, 0, buffer_len); + char cdb[] = {NEC_READ_CDDA, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + cdb[2] = (uint8_t)((lba & 0xFF000000) >> 24); + cdb[3] = (uint8_t)((lba & 0xFF0000) >> 16); + cdb[4] = (uint8_t)((lba & 0xFF00) >> 8); + cdb[5] = (uint8_t)(lba & 0xFF); + cdb[7] = (uint8_t)((transferLength & 0xFF00) >> 8); + cdb[8] = (uint8_t)(transferLength & 0xFF); + + int error = SendScsiCommand(fd, &cdb, cmd_len, *buffer, buffer_len, senseBuffer, SG_DXFER_FROM_DEV); + + return error; +} + +int HlDtStReadRawDvd(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint32_t lba, uint32_t transferLength) +{ + unsigned char cmd_len = 12; + uint32_t buffer_len = transferLength * 2064; + *buffer = malloc(buffer_len); + memset(*buffer, 0, buffer_len); + char cdb[] = {HLDTST_VENDOR, 0x48, 0x49, 0x54, 0x01, 0, 0, 0, 0, 0, 0, 0}; + + cdb[6] = (uint8_t)((lba & 0xFF000000) >> 24); + cdb[7] = (uint8_t)((lba & 0xFF0000) >> 16); + cdb[8] = (uint8_t)((lba & 0xFF00) >> 8); + cdb[9] = (uint8_t)(lba & 0xFF); + cdb[10] = (uint8_t)((buffer_len & 0xFF00) >> 8); + cdb[11] = (uint8_t)(buffer_len & 0xFF); + + int error = SendScsiCommand(fd, &cdb, cmd_len, *buffer, buffer_len, senseBuffer, SG_DXFER_FROM_DEV); + + return error; +} + diff --git a/DiscImageChef.Device.Report/scsi.h b/DiscImageChef.Device.Report/scsi.h index 241d20b28..584cbb8d7 100644 --- a/DiscImageChef.Device.Report/scsi.h +++ b/DiscImageChef.Device.Report/scsi.h @@ -36,6 +36,17 @@ int ReadLong16(int fd, unsigned char **buffer, unsigned char **senseBuffer, int int Seek6(int fd, unsigned char **senseBuffer, uint32_t lba); int Seek10(int fd, unsigned char **senseBuffer, uint32_t lba); int TestUnitReady(int fd, unsigned char **senseBuffer); +int GetConfiguration(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint16_t startingFeatureNumber, uint8_t RT); +int ReadTocPmaAtip(int fd, unsigned char **buffer, unsigned char **senseBuffer, int MSF, uint8_t format, uint8_t trackSessionNumber); +int ReadDiscStructure(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint8_t mediaType, uint32_t address, uint8_t layerNumber, uint8_t format, uint8_t AGID); +int ReadCd(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint32_t lba, uint32_t blockSize, uint32_t transferLength, uint8_t expectedSectorType, int DAP, int relAddr, int sync, uint8_t headerCodes, int userData, int edcEcc, uint8_t C2Error, uint8_t subchannel); +int ReadCdMsf(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint32_t startMsf, uint32_t endMsf, uint32_t blockSize, uint8_t expectedSectorType, int DAP, int sync, uint8_t headerCodes, int userData, int edcEcc, uint8_t C2Error, uint8_t subchannel); +int PlextorReadCdDa(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint32_t lba, uint32_t blockSize, uint32_t transferLength, uint8_t subchannel); +int PlextorReadRawDvd(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint32_t lba, uint32_t transferLength); +int PioneerReadCdDa(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint32_t lba, uint32_t blockSize, uint32_t transferLength, uint8_t subchannel); +int PioneerReadCdDaMsf(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint32_t startMsf, uint32_t endMsf, uint32_t blockSize, uint8_t subchannel); +int NecReadCdDa(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint32_t lba, uint32_t transferLength); +int HlDtStReadRawDvd(int fd, unsigned char **buffer, unsigned char **senseBuffer, uint32_t lba, uint32_t transferLength); typedef enum { @@ -51,11 +62,21 @@ typedef enum SCSI_READ_10 = 0x28, SCSI_READ_LONG = 0x3E, SCSI_SEEK_10 = 0x2B, + SCSI_READ_BUFFER = 0x3C, + MMC_READ_TOC_PMA_ATIP = 0x43, + MMC_GET_CONFIGURATION = 0x46, SCSI_MODE_SENSE_10 = 0x5A, SCSI_ATA_PASSTHROUGH_16 = 0x85, SCSI_READ_16 = 0x88, SCSI_SERVICE_ACTION_IN = 0x9E, SCSI_READ_12 = 0xA8, + MMC_READ_DISC_STRUCTURE = 0xAD, + MMC_READ_CD_MSF = 0xB9, + MMC_READ_CD = 0xBE, + NEC_READ_CDDA = 0xD4, + PIONEER_READ_CDDA = 0xD8, + PIONEER_READ_CDDA_MSF = 0xD9, + HLDTST_VENDOR = 0xE7, } ScsiCommands; typedef enum @@ -72,6 +93,253 @@ typedef enum SCSI_READ_LONG_16 = 0x11, } ScsiServiceActionIn; +typedef enum +{ + DISC_STRUCTURE_DVD = 0x00, + DISC_STRUCTURE_BD = 0x01, +} MmcDiscStructureMediaType; + +// TODO: Stylize this +typedef enum +{ + // Generic Format Codes + + /// + /// AACS Volume Identifier + /// + DISC_STRUCTURE_AACSVolId = 0x80, + /// + /// AACS Pre-recorded Media Serial Number + /// + DISC_STRUCTURE_AACSMediaSerial = 0x81, + /// + /// AACS Media Identifier + /// + DISC_STRUCTURE_AACSMediaId = 0x82, + /// + /// AACS Lead-in Media Key Block + /// + DISC_STRUCTURE_AACSMKB = 0x83, + /// + /// AACS Data Keys + /// + DISC_STRUCTURE_AACSDataKeys = 0x84, + /// + /// AACS LBA extents + /// + DISC_STRUCTURE_AACSLBAExtents = 0x85, + /// + /// CPRM Media Key Block specified by AACS + /// + DISC_STRUCTURE_AACSMKBCPRM = 0x86, + /// + /// Recognized format layers + /// + DISC_STRUCTURE_RecognizedFormatLayers = 0x90, + /// + /// Write protection status + /// + DISC_STRUCTURE_WriteProtectionStatus = 0xC0, + /// + /// READ/SEND DISC STRUCTURE capability list + /// + DISC_STRUCTURE_CapabilityList = 0xFF, + + // DVD Disc Structures + /// + /// DVD Lead-in Physical Information + /// + DISC_STRUCTURE_PhysicalInformation = 0x00, + /// + /// DVD Lead-in Copyright Information + /// + DISC_STRUCTURE_CopyrightInformation = 0x01, + /// + /// CSS/CPPM Disc key + /// + DISC_STRUCTURE_DiscKey = 0x02, + /// + /// DVD Burst Cutting Area + /// + DISC_STRUCTURE_BurstCuttingArea = 0x03, + /// + /// DVD Lead-in Disc Manufacturing Information + /// + DISC_STRUCTURE_DiscManufacturingInformation = 0x04, + /// + /// DVD Copyright Information from specified sector + /// + DISC_STRUCTURE_SectorCopyrightInformation = 0x05, + /// + /// CSS/CPPM Media Identifier + /// + DISC_STRUCTURE_MediaIdentifier = 0x06, + /// + /// CSS/CPPM Media Key Block + /// + DISC_STRUCTURE_MediaKeyBlock = 0x07, + /// + /// DDS from DVD-RAM + /// + DISC_STRUCTURE_DVDRAM_DDS = 0x08, + /// + /// DVD-RAM Medium Status + /// + DISC_STRUCTURE_DVDRAM_MediumStatus = 0x09, + /// + /// DVD-RAM Spare Area Information + /// + DISC_STRUCTURE_DVDRAM_SpareAreaInformation = 0x0A, + /// + /// DVD-RAM Recording Type Information + /// + DISC_STRUCTURE_DVDRAM_RecordingType = 0x0B, + /// + /// DVD-R/-RW RMD in last Border-out + /// + DISC_STRUCTURE_LastBorderOutRMD = 0x0C, + /// + /// Specified RMD from last recorded Border-out + /// + DISC_STRUCTURE_SpecifiedRMD = 0x0D, + /// + /// DVD-R/-RW Lead-in pre-recorded information + /// + DISC_STRUCTURE_PreRecordedInfo = 0x0E, + /// + /// DVD-R/-RW Media Identifier + /// + DISC_STRUCTURE_DVDR_MediaIdentifier = 0x0F, + /// + /// DVD-R/-RW Physical Format Information + /// + DISC_STRUCTURE_DVDR_PhysicalInformation = 0x10, + /// + /// ADIP + /// + DISC_STRUCTURE_ADIP = 0x11, + /// + /// HD DVD Lead-in Copyright Protection Information + /// + DISC_STRUCTURE_HDDVD_CopyrightInformation = 0x12, + /// + /// AACS Lead-in Copyright Data Section + /// + DISC_STRUCTURE_DVD_AACS = 0x15, + /// + /// HD DVD-R Medium Status + /// + DISC_STRUCTURE_HDDVDR_MediumStatus = 0x19, + /// + /// HD DVD-R Last recorded RMD in the latest RMZ + /// + DISC_STRUCTURE_HDDVDR_LastRMD = 0x1A, + /// + /// DVD+/-R DL and DVD-Download DL layer capacity + /// + DISC_STRUCTURE_DVDR_LayerCapacity = 0x20, + /// + /// DVD-R DL Middle Zone start address + /// + DISC_STRUCTURE_MiddleZoneStart = 0x21, + /// + /// DVD-R DL Jump Interval Size + /// + DISC_STRUCTURE_JumpIntervalSize = 0x22, + /// + /// DVD-R DL Start LBA of the manual layer jump + /// + DISC_STRUCTURE_ManualLayerJumpStartLBA = 0x23, + /// + /// DVD-R DL Remapping information of the specified Anchor Point + /// + DISC_STRUCTURE_RemapAnchorPoint = 0x24, + /// + /// Disc Control Block + /// + DISC_STRUCTURE_DCB = 0x30, + + // BD Disc Structures + /// + /// Blu-ray Disc Information + /// + DISC_STRUCTURE_DiscInformation = 0x00, + /// + /// Blu-ray Burst Cutting Area + /// + DISC_STRUCTURE_BD_BurstCuttingArea = 0x03, + /// + /// Blu-ray DDS + /// + DISC_STRUCTURE_BD_DDS = 0x08, + /// + /// Blu-ray Cartridge Status + /// + DISC_STRUCTURE_CartridgeStatus = 0x09, + /// + /// Blu-ray Spare Area Information + /// + DISC_STRUCTURE_BD_SpareAreaInformation = 0x0A, + /// + /// Unmodified DFL + /// + DISC_STRUCTURE_RawDFL = 0x12, + /// + /// Physical Access Control + /// + DISC_STRUCTURE_PAC = 0x30 +} MmcDiscStructureFormat; + +typedef enum +{ + MMC_SECTOR_ALL = 0, + MMC_SECTOR_CDDA = 1, + MMC_SECTOR_MODE1 = 2, + MMC_SECTOR_MODE2 = 3, + MMC_SECTOR_MODE2F1 = 4, + MMC_SECTOR_MODE2F2 = 5 +} MmcSectorTypes; + +typedef enum +{ + MMC_HEADER_NONE = 0, + MMC_HEADER_ONLY = 1, + MMC_SUBHEADER_ONLY = 2, + MMC_HEADER_ALL = 3 +} MmcHeaderCodes; + +typedef enum +{ + MMC_ERROR_NONE = 0, + MMC_ERROR_C2 = 1, + MMC_ERROR_C2_AND_BLOCK = 2 +} MmcErrorField; + +typedef enum +{ + MMC_SUBCHANNEL_NONE = 0, + MMC_SUBCHANNEL_RAW = 1, + MMC_SUBCHANNEL_Q16 = 2, + MMC_SUBCHANNEL_RW = 4 +} MmcSubchannel; + +typedef enum +{ + PIONEER_SUBCHANNEL_NONE = 0, + PIONEER_SUBCHANNEL_Q16 = 1, + PIONEER_SUBCHANNEL_ALL = 2, + PIONEER_SUBCHANNEL_ONLY = 3 +} PioneerSubchannel; + +typedef enum +{ + PLEXTOR_SUBCHANNEL_NONE = 0, + PLEXTOR_SUBCHANNEL_Q16 = 1, + PLEXTOR_SUBCHANNEL_PACK = 2, + PLEXTOR_SUBCHANNEL_ALL = 3, + PLEXTOR_SUBCHANNEL_RAW_C2 = 8 +} PlextorSubchannel; + // SCSI INQUIRY command response #pragma pack(push, 1) typedef struct diff --git a/DiscImageChef.Device.Report/scsi_report.c b/DiscImageChef.Device.Report/scsi_report.c index a8190bd3d..55bac98ae 100644 --- a/DiscImageChef.Device.Report/scsi_report.c +++ b/DiscImageChef.Device.Report/scsi_report.c @@ -9,6 +9,7 @@ #include "scsi.h" #include "inquiry_decode.h" #include "scsi_mode.h" +#include "mmc_report.h" void ScsiReport(int fd, xmlTextWriterPtr xmlWriter) { @@ -200,7 +201,8 @@ void ScsiReport(int fd, xmlTextWriterPtr xmlWriter) xmlTextWriterEndElement(xmlWriter); } - DecodedMode *decMode; + DecodedMode *decMode = NULL; + unsigned char* cdromMode = NULL; if(supportsMode10) decMode = DecodeMode10(mode10Response, inquiry->PeripheralDeviceType); @@ -235,7 +237,7 @@ void ScsiReport(int fd, xmlTextWriterPtr xmlWriter) if(page == 0x2A && subpage == 0x00) { - // TODO: Decode CD-ROM page + cdromMode = decMode->Pages[0x2A][0x00]; } } } @@ -245,7 +247,7 @@ void ScsiReport(int fd, xmlTextWriterPtr xmlWriter) if(inquiry->PeripheralDeviceType == 0x05) // MultiMediaDevice { - // TODO: Report MMC + MmcReport(fd, xmlWriter, cdromMode); } else if(inquiry->PeripheralDeviceType == 0x01) // SequentialAccess { @@ -416,7 +418,7 @@ void ScsiReport(int fd, xmlTextWriterPtr xmlWriter) } } - printf("Trying SCSI READ LONG (10)...\n"); + printf("Trying SCSI READ LONG (16)...\n"); ReadLong16(fd, &buffer, &sense, FALSE, 0, 0xFFFF); if((sense[0] == 0x70 || sense[0] == 0x71) && (sense[2] & 0x0F) == 0x05 && sense[12] == 0x24 && sense[13] == 0x00) xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsReadLong16", "%s", "true"); @@ -616,7 +618,7 @@ void ScsiReport(int fd, xmlTextWriterPtr xmlWriter) } } - printf("Trying SCSI READ LONG (10)...\n"); + printf("Trying SCSI READ LONG (16)...\n"); ReadLong16(fd, &buffer, &sense, FALSE, 0, 0xFFFF); if((sense[0] == 0x70 || sense[0] == 0x71) && (sense[2] & 0x0F) == 0x05 && sense[12] == 0x24 && sense[13] == 0x00) xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsReadLong16", "%s", "true");