mirror of
https://github.com/StrikerX3/StrikeBox.git
synced 2024-06-23 14:53:22 -04:00
Basic DVD image reader
Implemented SCSI READ(10) command
This commit is contained in:
parent
52b2549ac5
commit
d94bdf2225
|
@ -207,6 +207,8 @@ void ATAChannel::WriteCommand(uint8_t value) {
|
|||
return;
|
||||
}
|
||||
|
||||
//log_spew("ATAChannel::WriteCommand: Processing command 0x%x for channel %d, device %d\n", cmd, m_channel, devIndex);
|
||||
|
||||
// Instantiate the command
|
||||
auto factory = kCmdFactories.at(cmd);
|
||||
m_currentCommand = factory(*dev);
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
|
||||
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
|
||||
//
|
||||
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
|
||||
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
|
||||
//
|
||||
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
|
||||
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
|
||||
//
|
||||
|
@ -31,6 +34,12 @@ namespace vixen {
|
|||
namespace hw {
|
||||
namespace atapi {
|
||||
|
||||
// --- Sizes and capacities ---------------------------------------------------
|
||||
|
||||
const uint16_t kDVDSectorSize = 2048;
|
||||
const uint32_t kMaxSectorsDVDSingleLayer = 2298496; // 4.7 GiB
|
||||
const uint32_t kMaxSectorsDVDDualLayer = 4171712; // 8.5 GiB
|
||||
|
||||
// --- Command Descriptor Block (CDB) [p 4.3] ---------------------------------
|
||||
|
||||
// [p 4.3.4.1] Operation Code
|
||||
|
@ -109,25 +118,42 @@ union CommandDescriptorBlock {
|
|||
// [p 6.10 table 99] [s 3.12 table 75]
|
||||
// CDB for the MODE SENSE (10) command
|
||||
struct ModeSense10 {
|
||||
OperationCode opCode; // byte 0 Operation Code (0x5A)
|
||||
uint8_t _reserved1 : 3; // byte 1 [2:0] Reserved
|
||||
uint8_t disableBlockDescriptors : 1; // byte 1 [3] (DBD) Disable Block Descriptors
|
||||
uint8_t longLBAAccepted : 1; // byte 1 [4] (LLBAA) Long LBA Accepted
|
||||
uint8_t _reserved2 : 3; // byte 1 [7:5] Reserved
|
||||
uint8_t pageCode : 6; // byte 2 [5:0] Page code
|
||||
uint8_t pageControl : 2; // byte 2 [7:6] (PC) Page control
|
||||
uint8_t subpageCode; // byte 3 Subpage code
|
||||
uint8_t _reserved3[3]; // byte 4-6 Reserved
|
||||
uint8_t length[2]; // byte 7-8 Allocation Length
|
||||
uint8_t control; // byte 9 Control
|
||||
OperationCode opCode; // byte 0 Operation Code (0x5A)
|
||||
uint8_t _reserved1 : 3; // byte 1 [2:0] Reserved
|
||||
uint8_t disableBlockDescriptors : 1; // byte 1 [3] (DBD) Disable Block Descriptors
|
||||
uint8_t longLBAAccepted : 1; // byte 1 [4] (LLBAA) Long LBA Accepted
|
||||
uint8_t _reserved2 : 3; // byte 1 [7:5] Reserved
|
||||
uint8_t pageCode : 6; // byte 2 [5:0] Page code
|
||||
uint8_t pageControl : 2; // byte 2 [7:6] (PC) Page control
|
||||
uint8_t subpageCode; // byte 3 Subpage code
|
||||
uint8_t _reserved3[3]; // byte 4-6 Reserved
|
||||
uint8_t length[2]; // byte 7-8 Allocation Length
|
||||
uint8_t control; // byte 9 Control
|
||||
} modeSense10;
|
||||
|
||||
// [b 5.11 table 56]
|
||||
// CDB for the READ (10) command
|
||||
struct Read10 {
|
||||
OperationCode opCode; // byte 0 Operation Code (0x28)
|
||||
uint8_t _obsolete1 : 1; // byte 1 [0] Obsolete
|
||||
uint8_t forceUnitAccessNVCache : 1; // byte 1 [1] (FUA_NV) Force unit access non-volatile cache (read from/write to block cache before medium)
|
||||
uint8_t _reserved1 : 1; // byte 1 [2] Reserved
|
||||
uint8_t forceUnitAccess : 1; // byte 1 [3] (FUA) Force unit access (force access to media instead of cache)
|
||||
uint8_t disablePageOut : 1; // byte 1 [4] (DPO) Disable page out (do not cache block)
|
||||
uint8_t readProtect : 3; // byte 1 [7:5] (RDPROTECT) Read protect
|
||||
uint8_t lba[4]; // byte 2-5 Logical Block Address
|
||||
uint8_t groupNumber : 5; // byte 6 [4:0] Group number
|
||||
uint8_t _reserved2 : 3; // byte 6 [7:5] Reserved
|
||||
uint8_t length[2]; // byte 7-8 Transfer length
|
||||
uint8_t control; // byte 9 Control
|
||||
} read10;
|
||||
|
||||
// [m 5.16 table 144]
|
||||
// CDB for the READ CAPACITY command
|
||||
struct ReadCapacity {
|
||||
OperationCode opCode; // byte 0 Operation Code (0x25)
|
||||
uint8_t _reservedOrObsolete[8]; // byte 1-8 Reserved or obsolete fields
|
||||
uint8_t control; // byte 9 Control
|
||||
OperationCode opCode; // byte 0 Operation Code (0x25)
|
||||
uint8_t _reservedOrObsolete[8]; // byte 1-8 Reserved or obsolete fields
|
||||
uint8_t control; // byte 9 Control
|
||||
} readCapacity;
|
||||
|
||||
// [p 6.27 table 169] [s 3.37 table 164]
|
||||
|
@ -162,6 +188,7 @@ enum PageControl : uint8_t {
|
|||
// Operation Codes
|
||||
enum Operations : uint8_t {
|
||||
OpModeSense10 = 0x5A, // (0x5A) MODE SENSE (10 bytes)
|
||||
OpRead10 = 0x28, // (0x28) READ (10 bytes)
|
||||
OpReadCapacity = 0x25, // (0x25) READ CAPACITY
|
||||
OpRequestSense = 0x03, // (0x03) REQUEST SENSE
|
||||
OpTestUnitReady = 0x00, // (0x00) TEST UNIT READY
|
||||
|
@ -209,6 +236,7 @@ enum PacketOperationType {
|
|||
// Maps operation codes to their types
|
||||
const std::unordered_map<uint8_t, PacketOperationType, std::hash<uint8_t>> kOperationTypes = {
|
||||
{ OpModeSense10, PktOpDataIn },
|
||||
{ OpRead10, PktOpDataIn },
|
||||
{ OpReadCapacity, PktOpDataIn },
|
||||
{ OpRequestSense, PktOpDataIn },
|
||||
{ OpTestUnitReady, PktOpNonData },
|
||||
|
|
|
@ -173,7 +173,7 @@ void PacketProtocolCommand::WriteData(uint8_t *value, uint32_t size) {
|
|||
}
|
||||
|
||||
void PacketProtocolCommand::ProcessPacket() {
|
||||
log_debug("PacketProtocolCommand::ProcessPacket: Processing packet\n");
|
||||
//log_spew("PacketProtocolCommand::ProcessPacket: Processing packet\n");
|
||||
m_regs.status |= StBusy;
|
||||
m_regs.status &= ~StDataRequest;
|
||||
|
||||
|
|
|
@ -28,6 +28,18 @@ BaseDVDDriveATADeviceDriver::BaseDVDDriveATADeviceDriver() {
|
|||
BaseDVDDriveATADeviceDriver::~BaseDVDDriveATADeviceDriver() {
|
||||
}
|
||||
|
||||
bool BaseDVDDriveATADeviceDriver::Read(uint64_t byteAddress, uint8_t * buffer, uint32_t size) {
|
||||
// Always fail; this function should never be called on devices that support the PACKET Command feature set
|
||||
log_warning("BaseDVDDriveATADeviceDriver::Read: Unexpected ATA read\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BaseDVDDriveATADeviceDriver::Write(uint64_t byteAddress, uint8_t * buffer, uint32_t size) {
|
||||
// Always fail; this function should never be called on devices that support the PACKET Command feature set
|
||||
log_warning("BaseDVDDriveATADeviceDriver::Write: Unexpected ATA write\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
void BaseDVDDriveATADeviceDriver::IdentifyDevice(IdentifyDeviceData *data) {
|
||||
// Should never be invoked since this device supports the PACKET Command feature set
|
||||
// Fill with zeros just in case
|
||||
|
|
|
@ -42,8 +42,8 @@ public:
|
|||
|
||||
// ----- Data access ------------------------------------------------------
|
||||
|
||||
virtual bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override = 0;
|
||||
virtual bool Write(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override = 0;
|
||||
bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override;
|
||||
bool Write(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override;
|
||||
|
||||
// ----- ATAPI ------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -32,19 +32,6 @@ DummyDVDDriveATADeviceDriver::DummyDVDDriveATADeviceDriver() {
|
|||
DummyDVDDriveATADeviceDriver::~DummyDVDDriveATADeviceDriver() {
|
||||
}
|
||||
|
||||
bool DummyDVDDriveATADeviceDriver::Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) {
|
||||
// Fill with zeros, as if the disk was blank
|
||||
memset(buffer, 0, size);
|
||||
|
||||
// Always succeed
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DummyDVDDriveATADeviceDriver::Write(uint64_t byteAddress, uint8_t *buffer, uint32_t size) {
|
||||
// Lie about writing, always fail
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DummyDVDDriveATADeviceDriver::ValidateATAPIPacket(PacketInformation& packetInfo) {
|
||||
log_debug("DummyDVDDriveATADeviceDriver::ValidateATAPIPacket: Operation code 0x%x\n", packetInfo.cdb.opCode.u8, packetInfo.cdb.opCode.fields.commandCode, packetInfo.cdb.opCode.fields.groupCode);
|
||||
|
||||
|
@ -74,7 +61,7 @@ bool DummyDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead(PacketInformation&
|
|||
switch (packetInfo.cdb.modeSense10.pageCode) {
|
||||
case kPageCodeAuthentication:
|
||||
{
|
||||
// TODO: handle partial reads
|
||||
// TODO: handle partial reads (if those ever happen here)
|
||||
if (byteCountLimit < sizeof(XboxDVDAuthentication)) {
|
||||
packetInfo.result.aborted = true;
|
||||
packetInfo.result.deviceFault = true;
|
||||
|
@ -96,6 +83,15 @@ bool DummyDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead(PacketInformation&
|
|||
log_debug("DummyDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead: Unimplemented page code 0x%x for MODE SENSE(10)\n", packetInfo.cdb.modeSense10.pageCode);
|
||||
return false;
|
||||
}
|
||||
case OpRead10:
|
||||
{
|
||||
// Say that there is no disc in the drive
|
||||
packetInfo.result.status = StCheckCondition;
|
||||
packetInfo.result.senseKey = SKNotReady;
|
||||
packetInfo.result.additionalSenseCode = ASCMediumNotPresent;
|
||||
|
||||
return true;
|
||||
}
|
||||
case OpReadCapacity:
|
||||
{
|
||||
// Say that there is no disc in the drive
|
||||
|
|
|
@ -27,11 +27,6 @@ public:
|
|||
DummyDVDDriveATADeviceDriver();
|
||||
~DummyDVDDriveATADeviceDriver() override;
|
||||
|
||||
// ----- Data access ------------------------------------------------------
|
||||
|
||||
bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override;
|
||||
bool Write(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override;
|
||||
|
||||
// ----- ATAPI ------------------------------------------------------------
|
||||
|
||||
bool ValidateATAPIPacket(atapi::PacketInformation& packetInfo) override;
|
||||
|
|
208
src/core/vixen/hw/ata/drvs/drv_vdvd_image.cpp
Normal file
208
src/core/vixen/hw/ata/drvs/drv_vdvd_image.cpp
Normal file
|
@ -0,0 +1,208 @@
|
|||
// ATA/ATAPI-4 emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement a subset of the ATA/ATAPI-4 specification
|
||||
// that satisifies the requirements of an IDE interface for the Original Xbox.
|
||||
//
|
||||
// Specification:
|
||||
// http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification.
|
||||
#include "drv_vdvd_image.h"
|
||||
|
||||
#include "vixen/log.h"
|
||||
#include "vixen/io.h"
|
||||
#include "vixen/hw/ata/atapi_defs.h"
|
||||
#include "vixen/hw/ata/atapi_xbox.h"
|
||||
#include "vixen/hw/ata/atapi_utils.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace ata {
|
||||
|
||||
using namespace atapi;
|
||||
|
||||
ImageDVDDriveATADeviceDriver::ImageDVDDriveATADeviceDriver() {
|
||||
strcpy(m_serialNumber, "9876543210");
|
||||
strcpy(m_firmwareRevision, "1.00");
|
||||
strcpy(m_modelNumber, "IMAGE DVD 12345");
|
||||
}
|
||||
|
||||
ImageDVDDriveATADeviceDriver::~ImageDVDDriveATADeviceDriver() {
|
||||
}
|
||||
|
||||
bool ImageDVDDriveATADeviceDriver::LoadImageFile(const char *imagePath, bool copyOnWrite) {
|
||||
// TODO: Refactor image management into a class hierarchy:
|
||||
// IDiskImageProvider <<interface>>
|
||||
// XISODiskImageProvider
|
||||
// ...
|
||||
|
||||
// TODO: Use memory-mapped I/O
|
||||
|
||||
// Try to load the image file
|
||||
m_fpImage = NULL;
|
||||
auto err = fopen_s(&m_fpImage, imagePath, "rb");
|
||||
if (err) {
|
||||
log_fatal("ImageDVDDriveATADeviceDriver::LoadImage: Could not open image \"%s\": error code 0x%x\n", imagePath, err);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Determine image file size
|
||||
fseek(m_fpImage, 0, SEEK_END);
|
||||
uint64_t imageSize = _ftelli64(m_fpImage);
|
||||
uint64_t imageSizeInSectors = imageSize / kDVDSectorSize;
|
||||
log_info("ImageDVDDriveATADeviceDriver::LoadImage: Loaded image \"%s\": %llu bytes -> %llu sectors\n", imagePath, imageSize, imageSizeInSectors);
|
||||
if (imageSizeInSectors > kMaxSectorsDVDDualLayer) {
|
||||
log_warning("ImageDVDDriveATADeviceDriver::LoadImage: Image is too big; limiting to the first %u sectors\n", kMaxSectorsDVDDualLayer);
|
||||
imageSizeInSectors = kMaxSectorsDVDDualLayer;
|
||||
}
|
||||
|
||||
m_sectorCapacity = imageSizeInSectors;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImageDVDDriveATADeviceDriver::EjectMedia() {
|
||||
if (m_fpImage == NULL) {
|
||||
log_warning("ImageDVDDriveATADeviceDriver::EjectMedia: No media to eject\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
log_info("ImageDVDDriveATADeviceDriver::EjectMedia: Media ejected\n");
|
||||
fclose(m_fpImage);
|
||||
m_fpImage = NULL;
|
||||
// TODO: notify media removal
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImageDVDDriveATADeviceDriver::ValidateATAPIPacket(PacketInformation& packetInfo) {
|
||||
log_debug("ImageDVDDriveATADeviceDriver::ValidateATAPIPacket: Operation code 0x%x\n", packetInfo.cdb.opCode.u8, packetInfo.cdb.opCode.fields.commandCode, packetInfo.cdb.opCode.fields.groupCode);
|
||||
|
||||
// TODO: device-specific validation
|
||||
|
||||
// Check if the command is supported and has valid parameters.
|
||||
return ValidateCommand(packetInfo);
|
||||
}
|
||||
|
||||
bool ImageDVDDriveATADeviceDriver::ProcessATAPIPacketNonData(PacketInformation& packetInfo) {
|
||||
switch (packetInfo.cdb.opCode.u8) {
|
||||
case OpTestUnitReady:
|
||||
// If there is no disc in the drive, return the expected sense key and parameters.
|
||||
// The default values tell that there is media in the drive and the device is ready to accept commands.
|
||||
if (!HasMedia()) {
|
||||
packetInfo.result.status = StCheckCondition;
|
||||
packetInfo.result.senseKey = SKNotReady;
|
||||
packetInfo.result.additionalSenseCode = ASCMediumNotPresent;
|
||||
}
|
||||
|
||||
return true;
|
||||
default:
|
||||
log_debug("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketNonData: Unimplemented operation code 0x%x\n", packetInfo.cdb.opCode.u8);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead(PacketInformation& packetInfo, uint8_t *packetDataBuffer, uint16_t byteCountLimit, uint32_t *packetDataSize) {
|
||||
switch (packetInfo.cdb.opCode.u8) {
|
||||
case OpModeSense10:
|
||||
switch (packetInfo.cdb.modeSense10.pageCode) {
|
||||
case kPageCodeAuthentication:
|
||||
{
|
||||
// TODO: handle partial reads (if those ever happen here)
|
||||
if (byteCountLimit < sizeof(XboxDVDAuthentication)) {
|
||||
packetInfo.result.aborted = true;
|
||||
packetInfo.result.deviceFault = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fill in just enough information to pass basic authentication checks on modified kernels
|
||||
// TODO: Research Xbox DVD authentication
|
||||
// https://multimedia.cx/eggs/xbox-sphinx-protocol/
|
||||
XboxDVDAuthentication *dvdAuth = reinterpret_cast<XboxDVDAuthentication *>(packetDataBuffer);
|
||||
dvdAuth->CDFValid = 1;
|
||||
dvdAuth->PartitionArea = 1;
|
||||
dvdAuth->Authentication = 1;
|
||||
|
||||
*packetDataSize = sizeof(XboxDVDAuthentication);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
log_debug("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead: Unimplemented page code 0x%x for MODE SENSE(10)\n", packetInfo.cdb.modeSense10.pageCode);
|
||||
return false;
|
||||
}
|
||||
case OpRead10:
|
||||
{
|
||||
if (HasMedia()) {
|
||||
uint32_t lba = B2L32(packetInfo.cdb.read10.lba);
|
||||
uint16_t transferLength = B2L16(packetInfo.cdb.read10.length);
|
||||
|
||||
packetInfo.transferSize = transferLength * kDVDSectorSize;
|
||||
|
||||
// If this is the first read, fill in transfer data
|
||||
if (!m_transfer) {
|
||||
m_currentByte = lba * kDVDSectorSize;
|
||||
m_lastByte = m_currentByte + transferLength * kDVDSectorSize;
|
||||
}
|
||||
|
||||
// TODO: maybe handle caching? Could improve performance if accessing real media on supported drives
|
||||
|
||||
// Read from media
|
||||
uint16_t readLen = (byteCountLimit < m_lastByte - m_currentByte)
|
||||
? byteCountLimit
|
||||
: m_lastByte - m_currentByte;
|
||||
_fseeki64(m_fpImage, m_currentByte, SEEK_SET);
|
||||
|
||||
*packetDataSize = fread(packetDataBuffer, 1, readLen, m_fpImage);
|
||||
|
||||
// Update position
|
||||
m_currentByte += *packetDataSize;
|
||||
if (m_currentByte >= m_lastByte || *packetDataSize < readLen) {
|
||||
m_transfer = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Say that there is no disc in the drive
|
||||
packetInfo.result.status = StCheckCondition;
|
||||
packetInfo.result.senseKey = SKNotReady;
|
||||
packetInfo.result.additionalSenseCode = ASCMediumNotPresent;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
case OpReadCapacity:
|
||||
{
|
||||
ReadCapacityData *capData = reinterpret_cast<ReadCapacityData *>(packetDataBuffer);
|
||||
|
||||
if (HasMedia()) {
|
||||
L2B32(capData->lba, m_sectorCapacity);
|
||||
L2B32(capData->blockLength, kDVDSectorSize);
|
||||
}
|
||||
else {
|
||||
// Say that there is no disc in the drive
|
||||
packetInfo.result.status = StCheckCondition;
|
||||
packetInfo.result.senseKey = SKNotReady;
|
||||
packetInfo.result.additionalSenseCode = ASCMediumNotPresent;
|
||||
|
||||
L2B32(capData->lba, 0);
|
||||
L2B32(capData->blockLength, 0);
|
||||
}
|
||||
|
||||
*packetDataSize = sizeof(ReadCapacityData);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
log_debug("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead: Unimplemented operation code 0x%x\n", packetInfo.cdb.opCode.u8);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataWrite(PacketInformation& packetInfo, uint8_t *packetDataBuffer, uint16_t byteCountLimit) {
|
||||
|
||||
log_debug("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataWrite: Unimplemented operation code 0x%x\n", packetInfo.cdb.opCode.u8);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
63
src/core/vixen/hw/ata/drvs/drv_vdvd_image.h
Normal file
63
src/core/vixen/hw/ata/drvs/drv_vdvd_image.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
// ATA/ATAPI-4 emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement a subset of the ATA/ATAPI-4 specification
|
||||
// that satisifies the requirements of an IDE interface for the Original Xbox.
|
||||
//
|
||||
// Specification:
|
||||
// http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification.
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "drv_vdvd_base.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace ata {
|
||||
|
||||
/*!
|
||||
* A virtual DVD ATA device driver based on an image file.
|
||||
*
|
||||
* It can read/write directly to the image file or use write-on-copy, in which
|
||||
* case all writes done on a temporary file and subsequent reads to overwritten
|
||||
* sectors are redirected to the temporary file.
|
||||
*/
|
||||
class ImageDVDDriveATADeviceDriver : public BaseDVDDriveATADeviceDriver {
|
||||
public:
|
||||
ImageDVDDriveATADeviceDriver();
|
||||
~ImageDVDDriveATADeviceDriver() override;
|
||||
|
||||
// ----- Virtual DVD image management -------------------------------------
|
||||
|
||||
bool LoadImageFile(const char *imagePath, bool copyOnWrite);
|
||||
bool EjectMedia();
|
||||
|
||||
// ----- ATAPI ------------------------------------------------------------
|
||||
|
||||
bool ValidateATAPIPacket(atapi::PacketInformation& packetInfo) override;
|
||||
bool ProcessATAPIPacketNonData(atapi::PacketInformation& packetInfo) override;
|
||||
bool ProcessATAPIPacketDataRead(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit, uint32_t *packetDataSize) override;
|
||||
bool ProcessATAPIPacketDataWrite(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit) override;
|
||||
|
||||
private:
|
||||
FILE *m_fpImage = NULL;
|
||||
bool m_copyOnWrite;
|
||||
|
||||
inline bool HasMedia() { return m_fpImage != NULL; }
|
||||
|
||||
uint64_t m_sectorCapacity;
|
||||
|
||||
// ----- Transfer state ---------------------------------------------------
|
||||
|
||||
bool m_transfer = false;
|
||||
uint64_t m_currentByte;
|
||||
uint64_t m_lastByte;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
#include "vixen/hw/ata/drvs/drv_vhd_image.h"
|
||||
|
||||
#include "vixen/hw/ata/drvs/drv_vdvd_dummy.h"
|
||||
//#include "vixen/hw/ata/drvs/drv_vdvd_image.h"
|
||||
#include "vixen/hw/ata/drvs/drv_vdvd_image.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/mman.h>
|
||||
|
@ -395,9 +395,15 @@ EmulatorStatus Xbox::InitHardware() {
|
|||
m_ataDrivers[0][1] = new hw::ata::DummyDVDDriveATADeviceDriver();
|
||||
break;
|
||||
case VDVD_Image:
|
||||
// TODO: implement
|
||||
m_ataDrivers[0][1] = new hw::ata::NullATADeviceDriver();
|
||||
{
|
||||
auto imageVDVD = new hw::ata::ImageDVDDriveATADeviceDriver();
|
||||
if (!imageVDVD->LoadImageFile(m_settings.vdvd_parameters.image.path, m_settings.vdvd_parameters.image.preserveImage)) {
|
||||
log_fatal("Failed to load virtual DVD image file\n");
|
||||
return EMUS_INIT_DVD_DRIVE_INIT_FAILED;
|
||||
}
|
||||
m_ataDrivers[0][1] = imageVDVD;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
log_fatal("Invalid virtual DVD drive type specified: %d\n", m_settings.vdvd_type);
|
||||
return EMUS_INIT_INVALID_DVD_DRIVE_TYPE;
|
||||
|
|
Loading…
Reference in a new issue