mirror of
https://github.com/StrikerX3/StrikeBox.git
synced 2024-06-22 22:32:33 -04:00
Refactored ATAPI commands
READ (10) still doesn't work correctly with large transfers, but it's a huge step in the right direction
This commit is contained in:
parent
8cf4830d0c
commit
b68e17b1e9
|
@ -3,6 +3,8 @@ file(GLOB DIR_HEADERS
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/ata/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ata/cmds/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ata/drvs/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/atapi/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/atapi/cmds/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/basic/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/bus/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/sm/*.h
|
||||
|
@ -18,6 +20,8 @@ file(GLOB DIR_SOURCES
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/ata/*.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ata/cmds/*.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ata/drvs/*.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/atapi/*.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/atapi/cmds/*.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/basic/*.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/bus/*.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/sm/*.cpp
|
||||
|
|
|
@ -246,9 +246,6 @@ DMATransferResult ATAChannel::ReadDMA(uint8_t *dstBuffer, uint32_t readLen) {
|
|||
m_currentCommand->ReadData(dstBuffer, readLen);
|
||||
if (m_currentCommand->IsFinished()) {
|
||||
log_spew("ATAChannel::ReadDMA: Finished processing command for channel %d\n", m_channel);
|
||||
if (m_currentCommand == nullptr) {
|
||||
log_spew("This thing broke :(\n", m_channel);
|
||||
}
|
||||
delete m_currentCommand;
|
||||
m_currentCommand = nullptr;
|
||||
return DMATransferEnd;
|
||||
|
@ -270,9 +267,6 @@ DMATransferResult ATAChannel::WriteDMA(uint8_t *srcBuffer, uint32_t writeLen) {
|
|||
m_currentCommand->WriteData(srcBuffer, writeLen);
|
||||
if (m_currentCommand->IsFinished()) {
|
||||
log_spew("ATAChannel::WriteDMA: Finished processing command for channel %d\n", m_channel);
|
||||
if (m_currentCommand == nullptr) {
|
||||
log_spew("This thing broke :(\n", m_channel);
|
||||
}
|
||||
delete m_currentCommand;
|
||||
m_currentCommand = nullptr;
|
||||
return DMATransferEnd;
|
||||
|
|
|
@ -100,7 +100,7 @@ void DMAProtocolCommand::ReadData(uint8_t *value, uint32_t size) {
|
|||
|
||||
// If the device uses removable media, check if it has media
|
||||
// TODO: implement removable media functions in the driver
|
||||
/*if (m_driver->IsRemovableMedia() && !m_driver->HasMedia()) {
|
||||
/*if (m_driver->IsRemovableMedia() && !m_driver->HasMedium()) {
|
||||
// [8.23.6]: "NM shall be set to one if no media is present in a removable media device."
|
||||
m_regs.error |= ErrDMANoMedia;
|
||||
UnrecoverableError();
|
||||
|
@ -151,7 +151,7 @@ void DMAProtocolCommand::WriteData(uint8_t *value, uint32_t size) {
|
|||
|
||||
// If the device uses removable media, check if it has media
|
||||
// TODO: implement removable media functions in the driver
|
||||
/*if (m_driver->IsRemovableMedia() && !m_driver->HasMedia()) {
|
||||
/*if (m_driver->IsRemovableMedia() && !m_driver->HasMedium()) {
|
||||
// [8.23.6]: "NM shall be set to one if no media is present in a removable media device."
|
||||
m_regs.error |= ErrDMANoMedia;
|
||||
UnrecoverableError();
|
||||
|
|
|
@ -12,13 +12,18 @@
|
|||
#include "proto_packet.h"
|
||||
|
||||
#include "vixen/log.h"
|
||||
#include "../atapi_defs.h"
|
||||
#include "vixen/hw/atapi/atapi_defs.h"
|
||||
#include "vixen/hw/atapi/atapi_xbox.h"
|
||||
#include "vixen/hw/atapi/atapi_utils.h"
|
||||
#include "vixen/hw/atapi/cmds/atapi_command.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace ata {
|
||||
namespace cmd {
|
||||
|
||||
using namespace vixen::hw::atapi;
|
||||
|
||||
// Notes regarding the protocol:
|
||||
// - There are two fluxograms: PIO/non-data transfers and DMA transfers
|
||||
// - They're largely the same, except for the actual data transfer and some register flag manipulations
|
||||
|
@ -33,7 +38,7 @@ namespace cmd {
|
|||
// bit 2 (REL) (Overlapped only) Indicates that the device is performing a bus release
|
||||
// bit 1 (I/O) When set to 1, indicates a transfer to the host; 0 indicates transfer to the device
|
||||
// bit 0 (C/D) When set to 1, indicates a command packet; 0 indicates a data packet
|
||||
// - The Status register is largely the same, except for the following fields:
|
||||
// - The Status register includes the following fields:
|
||||
// bit 5 (DMRD) DMA ready
|
||||
// bit 4 (SERV) (Overlapped only) Indicates that another command can be serviced
|
||||
// bit 0 (CHK) Indicates an error; host should check the Error register sense key or code bit
|
||||
|
@ -44,9 +49,7 @@ namespace cmd {
|
|||
PacketProtocolCommand::PacketProtocolCommand(ATADevice& device)
|
||||
: IATACommand(device)
|
||||
, m_packetCmdBuffer(nullptr)
|
||||
, m_packetDataBuffer(nullptr)
|
||||
, m_packetDataPos(0)
|
||||
, m_packetDataSize(0)
|
||||
, m_command(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -54,84 +57,72 @@ PacketProtocolCommand::~PacketProtocolCommand() {
|
|||
if (m_packetCmdBuffer != nullptr) {
|
||||
delete[] m_packetCmdBuffer;
|
||||
}
|
||||
if (m_packetDataBuffer != nullptr) {
|
||||
delete[] m_packetDataBuffer;
|
||||
if (m_command != nullptr) {
|
||||
delete m_command;
|
||||
}
|
||||
}
|
||||
|
||||
void PacketProtocolCommand::Execute() {
|
||||
if (ReadInput()) {
|
||||
// Update Interrupt register
|
||||
m_regs.sectorCount |= PkIntrCmdOrData;
|
||||
m_regs.sectorCount &= ~PkIntrIODirection;
|
||||
// On PIO and non-data transfers, Bus Release is cleared
|
||||
if (!m_dmaTransfer) {
|
||||
m_regs.sectorCount &= ~PkIntrBusRelease;
|
||||
}
|
||||
|
||||
// Update Status register
|
||||
m_regs.status |= StDataRequest;
|
||||
m_regs.status &= ~StBusy;
|
||||
|
||||
// Allocate buffer for the packet
|
||||
m_packetCmdBuffer = new uint8_t[m_driver->GetPacketCommandSize()];
|
||||
m_packetCmdPos = 0;
|
||||
|
||||
// Follow (A) in the protocol fluxogram
|
||||
}
|
||||
else {
|
||||
HandleProtocolTail(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool PacketProtocolCommand::ReadInput() {
|
||||
// Read input according to the protocol [8.21.4]
|
||||
m_overlapped = !!(m_regs.features & PkFeatOverlapped);
|
||||
m_dmaTransfer = !!(m_regs.features & PkFeatDMATransfer);
|
||||
m_tag = (m_regs.sectorCount >> kPkTagShift) & kPkTagMask;
|
||||
m_byteCountLimit = m_regs.cylinder;
|
||||
m_selectedDevice = m_regs.GetSelectedDeviceIndex();
|
||||
m_packetCmdState.input.overlapped = !!(m_regs.features & PkFeatOverlapped);
|
||||
m_packetCmdState.input.dmaTransfer = !!(m_regs.features & PkFeatDMATransfer);
|
||||
m_packetCmdState.input.tag = (m_regs.sectorCount >> kPkTagShift) & kPkTagMask;
|
||||
m_packetCmdState.input.byteCountLimit = m_regs.cylinder;
|
||||
m_packetCmdState.input.selectedDevice = m_regs.GetSelectedDeviceIndex();
|
||||
|
||||
// If the byte count limit is zero, set ABRT and stop command
|
||||
if (m_packetCmdState.input.byteCountLimit == 0) {
|
||||
m_regs.error |= ErrAbort;
|
||||
HandleProtocolTail(true);
|
||||
return;
|
||||
}
|
||||
|
||||
return true;
|
||||
// A byte count limit of 0xFFFF is interpreted by the device as though it were 0xFFFE
|
||||
if (m_packetCmdState.input.byteCountLimit == 0xFFFF) {
|
||||
m_packetCmdState.input.byteCountLimit = 0xFFFE;
|
||||
}
|
||||
|
||||
// Update Interrupt register
|
||||
m_regs.sectorCount |= PkIntrCmdOrData;
|
||||
m_regs.sectorCount &= ~PkIntrIODirection;
|
||||
// On PIO and non-data transfers, Bus Release is cleared
|
||||
if (!m_packetCmdState.input.dmaTransfer) {
|
||||
m_regs.sectorCount &= ~PkIntrBusRelease;
|
||||
}
|
||||
|
||||
// Update Status register
|
||||
m_regs.status |= StDataRequest;
|
||||
m_regs.status &= ~StBusy;
|
||||
|
||||
// Allocate buffer for the packet
|
||||
m_packetCmdBuffer = new uint8_t[m_driver->GetPacketCommandSize()];
|
||||
m_packetCmdPos = 0;
|
||||
|
||||
// Follow (A) in the protocol fluxogram
|
||||
}
|
||||
|
||||
void PacketProtocolCommand::ReadData(uint8_t *value, uint32_t size) {
|
||||
// Host is reading the data requested by the Packet command
|
||||
|
||||
// If the packet data buffer is empty, ask driver to fill in a full block
|
||||
// of data (up to the byte count limit) and tell us how many bytes it filled
|
||||
if (m_packetDataSize == 0) {
|
||||
// Let the driver fill in the data buffer
|
||||
if (!m_driver->ProcessATAPIPacketDataRead(m_packetInfo, m_packetDataBuffer, m_byteCountLimit, &m_packetDataSize)) {
|
||||
HandleProtocolTail(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy from buffer to value
|
||||
// TODO: handle partial transfers
|
||||
memcpy(value, m_packetDataBuffer + m_packetDataPos, size);
|
||||
m_packetDataPos += size;
|
||||
// Read from buffer
|
||||
uint32_t sizeRead = m_packetCmdState.dataBuffer.Read(value, size);
|
||||
|
||||
// Done reading the packet data?
|
||||
if (m_packetDataPos >= m_packetDataSize) {
|
||||
if (m_packetCmdState.dataBuffer.IsReadFinished()) {
|
||||
m_regs.status |= StBusy;
|
||||
m_regs.status &= ~StDataRequest;
|
||||
|
||||
// Done transferring all the data needed by the packet?
|
||||
m_packetDataTotal += m_packetDataPos;
|
||||
if (m_packetDataTotal >= m_packetInfo.transferSize) {
|
||||
if (m_command->IsTransferFinished()) {
|
||||
HandleProtocolTail(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Let the driver fill in the data buffer again
|
||||
if (!m_driver->ProcessATAPIPacketDataRead(m_packetInfo, m_packetDataBuffer, m_byteCountLimit, &m_packetDataSize)) {
|
||||
// Read more data
|
||||
if (!m_command->Execute()) {
|
||||
HandleProtocolTail(true);
|
||||
return;
|
||||
}
|
||||
|
||||
m_packetDataPos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,29 +140,26 @@ void PacketProtocolCommand::WriteData(uint8_t *value, uint32_t size) {
|
|||
}
|
||||
else {
|
||||
// Writing the data requested by the Packet command
|
||||
// TODO: handle partial transfers
|
||||
memcpy(m_packetDataBuffer + m_packetDataPos, value, size);
|
||||
m_packetDataPos += size;
|
||||
|
||||
// Write to buffer
|
||||
uint32_t sizeWritten = m_packetCmdState.dataBuffer.Write(value, size);
|
||||
|
||||
// Done writing the packet data?
|
||||
if (m_packetDataPos >= m_byteCountLimit) {
|
||||
if (m_packetCmdState.dataBuffer.IsWriteFinished()) {
|
||||
m_regs.status |= StBusy;
|
||||
m_regs.status &= ~StDataRequest;
|
||||
|
||||
// Let the driver process the data
|
||||
if (!m_driver->ProcessATAPIPacketDataWrite(m_packetInfo, m_packetDataBuffer, m_byteCountLimit)) {
|
||||
|
||||
// Execute command with the current buffer
|
||||
if (!m_command->Execute()) {
|
||||
HandleProtocolTail(true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Done transferring all the data needed by the packet?
|
||||
m_packetDataTotal += m_packetDataPos;
|
||||
if (m_packetDataTotal >= m_packetInfo.transferSize) {
|
||||
if (m_command->IsTransferFinished()) {
|
||||
HandleProtocolTail(false);
|
||||
return;
|
||||
}
|
||||
|
||||
m_packetDataPos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -181,63 +169,45 @@ void PacketProtocolCommand::ProcessPacket() {
|
|||
m_regs.status |= StBusy;
|
||||
m_regs.status &= ~StDataRequest;
|
||||
|
||||
// Identify packet
|
||||
// Get the command descriptor block
|
||||
atapi::CommandDescriptorBlock *cdb = reinterpret_cast<atapi::CommandDescriptorBlock *>(m_packetCmdBuffer);
|
||||
|
||||
// Check that there is an operation type for the operation code.
|
||||
// Every command must have an operation type.
|
||||
if (atapi::kOperationTypes.count(cdb->opCode.u8) == 0) {
|
||||
|
||||
// Get the command factory for the command's operation code
|
||||
if (kCmdFactories.count(cdb->opCode.u8) == 0) {
|
||||
log_warning("PacketProtocolCommand::ProcessPacket: Unimplemented command 0x%x!\n", cdb->opCode.u8);
|
||||
HandleProtocolTail(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare packet info data
|
||||
m_packetInfo.cdb = *cdb;
|
||||
m_packetInfo.opType = atapi::kOperationTypes.at(cdb->opCode.u8);
|
||||
log_spew("PacketProtocolCommand::ProcessPacket: Processing command 0x%x\n", cdb->opCode.u8);
|
||||
|
||||
// Check if the device can process the packet
|
||||
bool succeeded = m_driver->ValidateATAPIPacket(m_packetInfo);
|
||||
// Instantiate the command.
|
||||
// This will also allocate the data buffer if necessary.
|
||||
m_packetCmdState.cdb = *cdb;
|
||||
auto factory = kCmdFactories.at(cdb->opCode.u8);
|
||||
m_command = factory(m_packetCmdState, m_driver);
|
||||
|
||||
// Handle error
|
||||
if (!succeeded) {
|
||||
// Validate parameters; return error immediately if invalid.
|
||||
// Will also initialize the data buffer if a transfer is required.
|
||||
if (!m_command->Prepare()) {
|
||||
HandleProtocolTail(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the byte count limit is zero, set ABRT and stop command
|
||||
if (m_byteCountLimit == 0) {
|
||||
m_regs.error |= ErrAbort;
|
||||
HandleProtocolTail(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the total requested data transfer length is greater than the byte count limit, then the byte count limit must be even
|
||||
// If the total requested data transfer length is less than or equal to the byte count limit, then the byte count limit could be even or odd
|
||||
if (m_packetInfo.transferSize > m_byteCountLimit && (m_byteCountLimit & 1)) {
|
||||
m_regs.error |= ErrAbort;
|
||||
HandleProtocolTail(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// A byte count limit of 0xFFFF is interpreted by the device as though it were 0xFFFE
|
||||
if (m_byteCountLimit == 0xFFFF) {
|
||||
m_byteCountLimit = 0xFFFE;
|
||||
}
|
||||
|
||||
if (m_packetInfo.opType == atapi::PktOpNonData) {
|
||||
// Execute non-data command
|
||||
bool succeeded = m_driver->ProcessATAPIPacketNonData(m_packetInfo);
|
||||
if (m_command->GetOperationType() == PktOpNonData) {
|
||||
// Execute non-data command immediately
|
||||
bool succeeded = m_command->Execute();
|
||||
HandleProtocolTail(!succeeded);
|
||||
}
|
||||
else {
|
||||
// Prepare registers for a data transfer (in or out)
|
||||
PrepareDataTransfer();
|
||||
}
|
||||
}
|
||||
|
||||
void PacketProtocolCommand::PrepareDataTransfer() {
|
||||
// Check for overlapped execution (corresponds to (B) in the protocol fluxogram)
|
||||
if (m_driver->SupportsOverlap() && m_driver->IsOverlapEnabled() && m_overlapped) {
|
||||
if (m_driver->SupportsOverlap() && m_driver->IsOverlapEnabled() && m_packetCmdState.input.overlapped) {
|
||||
ProcessPacketOverlapped();
|
||||
}
|
||||
else {
|
||||
|
@ -246,7 +216,7 @@ void PacketProtocolCommand::PrepareDataTransfer() {
|
|||
}
|
||||
|
||||
void PacketProtocolCommand::ProcessPacketImmediate() {
|
||||
if (m_dmaTransfer) {
|
||||
if (m_packetCmdState.input.dmaTransfer) {
|
||||
m_regs.sectorCount &= ~PkIntrBusRelease;
|
||||
m_regs.status &= ~StService;
|
||||
m_regs.status |= StDMAReady;
|
||||
|
@ -254,14 +224,14 @@ void PacketProtocolCommand::ProcessPacketImmediate() {
|
|||
else {
|
||||
// Set Tag
|
||||
m_regs.sectorCount &= ~(kPkTagMask << kPkTagShift);
|
||||
m_regs.sectorCount |= m_tag << kPkTagShift;
|
||||
m_regs.sectorCount |= m_packetCmdState.input.tag << kPkTagShift;
|
||||
|
||||
// Set byte count
|
||||
m_regs.cylinder = m_byteCountLimit;
|
||||
m_regs.cylinder = m_packetCmdState.input.byteCountLimit;
|
||||
}
|
||||
|
||||
// Set I/O
|
||||
if (m_packetInfo.opType == atapi::PktOpDataOut) {
|
||||
if (m_command->GetOperationType() == atapi::PktOpDataOut) {
|
||||
m_regs.sectorCount |= PkIntrIODirection;
|
||||
}
|
||||
else {
|
||||
|
@ -275,12 +245,6 @@ void PacketProtocolCommand::ProcessPacketImmediate() {
|
|||
m_regs.status |= StDataRequest;
|
||||
m_regs.status &= ~StBusy;
|
||||
|
||||
// Allocate buffer for the data transfer
|
||||
m_packetDataBuffer = new uint8_t[m_byteCountLimit];
|
||||
m_packetDataPos = 0;
|
||||
m_packetDataTotal = 0;
|
||||
m_packetDataSize = 0;
|
||||
|
||||
m_interrupt.Assert();
|
||||
}
|
||||
|
||||
|
@ -298,13 +262,13 @@ void PacketProtocolCommand::HandleProtocolTail(bool hasError) {
|
|||
// Error register:
|
||||
// "Sense Key is a command packet set specific error indication."
|
||||
m_regs.error &= ~(kPkSenseMask << kPkSenseShift);
|
||||
m_regs.error |= (m_packetInfo.result.senseKey & kPkSenseMask) << kPkSenseShift;
|
||||
m_regs.error |= (m_packetCmdState.result.senseKey & kPkSenseMask) << kPkSenseShift;
|
||||
|
||||
// "ABRT shall be set to one if the requested command has been command
|
||||
// [sic] aborted because the command code or a command parameter is
|
||||
// invalid. ABRT may be set to one if the device is not able to
|
||||
// complete the action requested by the command."
|
||||
if (m_packetInfo.result.aborted) {
|
||||
if (m_packetCmdState.result.aborted) {
|
||||
m_regs.error |= ErrAbort;
|
||||
}
|
||||
else {
|
||||
|
@ -313,7 +277,7 @@ void PacketProtocolCommand::HandleProtocolTail(bool hasError) {
|
|||
|
||||
// "EOM - the meaning of this bit is command set specific. See the
|
||||
// appropriate command set standard for its definition."
|
||||
if (m_packetInfo.result.endOfMedium) {
|
||||
if (m_packetCmdState.result.endOfMedium) {
|
||||
m_regs.error |= PkErrEndOfMedium;
|
||||
}
|
||||
else {
|
||||
|
@ -322,7 +286,7 @@ void PacketProtocolCommand::HandleProtocolTail(bool hasError) {
|
|||
|
||||
// "ILI - the meaning of this bit is command set specific. See the
|
||||
// appropriate command set standard for its definition."
|
||||
if (m_packetInfo.result.incorrectLength) {
|
||||
if (m_packetCmdState.result.incorrectLength) {
|
||||
m_regs.error |= PkErrIncorrectLength;
|
||||
}
|
||||
else {
|
||||
|
@ -336,7 +300,7 @@ void PacketProtocolCommand::HandleProtocolTail(bool hasError) {
|
|||
// disabled, this field is not applicable."
|
||||
// We'll fill it in regardless of command queuing or overlap support
|
||||
m_regs.sectorCount &= ~(kPkTagMask << kPkTagShift);
|
||||
m_regs.sectorCount |= m_tag << kPkTagShift;
|
||||
m_regs.sectorCount |= m_packetCmdState.input.tag << kPkTagShift;
|
||||
|
||||
// "REL - Shall be cleared to zero."
|
||||
m_regs.sectorCount &= ~PkIntrBusRelease;
|
||||
|
@ -361,7 +325,7 @@ void PacketProtocolCommand::HandleProtocolTail(bool hasError) {
|
|||
// TODO: support overlapped operations
|
||||
|
||||
// "DF(Device Fault) shall be set to one if a device fault has occurred."
|
||||
if (m_packetInfo.result.deviceFault) {
|
||||
if (m_packetCmdState.result.deviceFault) {
|
||||
m_regs.status |= StDeviceFault;
|
||||
}
|
||||
|
||||
|
@ -375,7 +339,7 @@ void PacketProtocolCommand::HandleProtocolTail(bool hasError) {
|
|||
m_regs.sectorCount |= PkIntrIODirection | PkIntrCmdOrData;
|
||||
m_regs.sectorCount &= ~PkIntrBusRelease;
|
||||
|
||||
if (m_dmaTransfer) {
|
||||
if (m_packetCmdState.input.dmaTransfer) {
|
||||
m_regs.status &= ~StDataRequest;
|
||||
}
|
||||
m_regs.status |= StReady;
|
||||
|
|
|
@ -14,6 +14,11 @@
|
|||
#include <cstdint>
|
||||
|
||||
#include "ata_command.h"
|
||||
#include "vixen/hw/atapi/cmds/cmd_mode_sense_10.h"
|
||||
#include "vixen/hw/atapi/cmds/cmd_read_10.h"
|
||||
#include "vixen/hw/atapi/cmds/cmd_read_capacity.h"
|
||||
#include "vixen/hw/atapi/cmds/cmd_read_dvd_structure.h"
|
||||
#include "vixen/hw/atapi/cmds/cmd_test_unit_ready.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
|
@ -37,9 +42,6 @@ public:
|
|||
private:
|
||||
// ----- Protocol operations ----------------------------------------------
|
||||
|
||||
// Parses the input registers and stores the values in the parameters.
|
||||
bool ReadInput();
|
||||
|
||||
// Corresponds to the end of the protocol fluxogram starting from (C) when
|
||||
// hasError is true, or (D) if false.
|
||||
void HandleProtocolTail(bool hasError);
|
||||
|
@ -51,28 +53,30 @@ private:
|
|||
// Corresponds to the protocol fluxogram starting from (B).
|
||||
void PrepareDataTransfer();
|
||||
|
||||
// Prepares registers for an immediate (non-overlapped) data transfer.
|
||||
void ProcessPacketImmediate();
|
||||
|
||||
// Prepares registers for an overlapped data transfer.
|
||||
void ProcessPacketOverlapped();
|
||||
|
||||
// ----- Parameters -------------------------------------------------------
|
||||
|
||||
bool m_overlapped;
|
||||
bool m_dmaTransfer;
|
||||
uint8_t m_tag;
|
||||
uint16_t m_byteCountLimit;
|
||||
uint8_t m_selectedDevice;
|
||||
|
||||
// ----- State ------------------------------------------------------------
|
||||
|
||||
uint8_t *m_packetCmdBuffer;
|
||||
uint8_t m_packetCmdPos;
|
||||
|
||||
uint8_t *m_packetDataBuffer;
|
||||
uint16_t m_packetDataPos;
|
||||
uint32_t m_packetDataTotal;
|
||||
uint32_t m_packetDataSize;
|
||||
atapi::PacketCommandState m_packetCmdState;
|
||||
|
||||
atapi::PacketInformation m_packetInfo;
|
||||
atapi::cmd::IATAPICommand *m_command;
|
||||
};
|
||||
|
||||
// Map commands to their factories
|
||||
const std::unordered_map<uint8_t, atapi::cmd::IATAPICommand::Factory, std::hash<uint8_t>> kCmdFactories = {
|
||||
{ atapi::OpModeSense10, atapi::cmd::ModeSense10::Factory },
|
||||
{ atapi::OpRead10, atapi::cmd::Read10::Factory },
|
||||
{ atapi::OpReadCapacity, atapi::cmd::ReadCapacity::Factory },
|
||||
{ atapi::OpReadDVDStructure, atapi::cmd::ReadDVDStructure::Factory },
|
||||
//{ atapi::OpRequestSense, atapi::cmd::RequestSense::Factory },
|
||||
{ atapi::OpTestUnitReady, atapi::cmd::TestUnitReady::Factory },
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <cstdint>
|
||||
|
||||
#include "../../ata/ata_defs.h"
|
||||
#include "../../ata/atapi_common.h"
|
||||
#include "../../atapi/atapi_common.h"
|
||||
#include "../ata_common.h"
|
||||
#include "util.h"
|
||||
|
||||
|
@ -47,18 +47,17 @@ public:
|
|||
virtual bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) = 0;
|
||||
virtual bool Write(uint64_t byteAddress, uint8_t *buffer, uint32_t size) = 0;
|
||||
|
||||
// ----- ATAPI ------------------------------------------------------------
|
||||
|
||||
virtual bool ValidateATAPIPacket(atapi::PacketInformation& packetInfo) = 0;
|
||||
virtual bool ProcessATAPIPacketNonData(atapi::PacketInformation& packetInfo) = 0;
|
||||
virtual bool ProcessATAPIPacketDataRead(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit, uint32_t *packetDataSize) = 0;
|
||||
virtual bool ProcessATAPIPacketDataWrite(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit) = 0;
|
||||
|
||||
// ----- Feature sets -----------------------------------------------------
|
||||
|
||||
virtual bool SupportsPacketCommands() = 0;
|
||||
virtual bool SupportsOverlap() = 0;
|
||||
virtual bool IsOverlapEnabled() = 0;
|
||||
|
||||
// ----- Medium -----------------------------------------------------------
|
||||
|
||||
virtual bool HasMedium() = 0;
|
||||
virtual uint32_t GetMediumCapacitySectors() = 0;
|
||||
virtual uint32_t GetSectorSize() = 0;
|
||||
|
||||
// ----- Utility functions ------------------------------------------------
|
||||
|
||||
|
@ -67,6 +66,7 @@ public:
|
|||
virtual uint32_t CHSToLBA(uint32_t cylinder, uint8_t head, uint8_t sector) = 0;
|
||||
virtual void LBAToCHS(uint32_t lbaAddress, uint16_t *cylinder, uint8_t *head, uint8_t *sector) = 0;
|
||||
virtual uint8_t GetPacketCommandSize() = 0;
|
||||
|
||||
protected:
|
||||
// ----- Common data ------------------------------------------------------
|
||||
|
||||
|
|
|
@ -37,13 +37,6 @@ public:
|
|||
|
||||
bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override { return false; }
|
||||
bool Write(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override { return false; }
|
||||
// ----- ATAPI ------------------------------------------------------------
|
||||
|
||||
bool ValidateATAPIPacket(atapi::PacketInformation& packetInfo) override { return false; }
|
||||
bool ProcessATAPIPacketNonData(atapi::PacketInformation& packetInfo) override { return false; }
|
||||
bool ProcessATAPIPacketDataRead(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit, uint32_t *packetDataSize) override { return false; }
|
||||
bool ProcessATAPIPacketDataWrite(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit) override { return false; }
|
||||
|
||||
|
||||
// ----- Feature sets -----------------------------------------------------
|
||||
|
||||
|
@ -51,6 +44,12 @@ public:
|
|||
bool SupportsOverlap() override { return false; }
|
||||
bool IsOverlapEnabled() override { return false; }
|
||||
|
||||
// ----- Medium -----------------------------------------------------------
|
||||
|
||||
bool HasMedium() override { return false; }
|
||||
uint32_t GetMediumCapacitySectors() override { return 0; }
|
||||
uint32_t GetSectorSize() override { return kSectorSize; }
|
||||
|
||||
// ----- Utility functions ------------------------------------------------
|
||||
|
||||
bool IsAttached() override { return true; }
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
|
||||
#include "vixen/log.h"
|
||||
#include "vixen/io.h"
|
||||
#include "vixen/hw/ata/atapi_xbox.h"
|
||||
#include "vixen/hw/ata/atapi_utils.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
|
@ -28,15 +26,9 @@ 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");
|
||||
bool BaseDVDDriveATADeviceDriver::Write(uint64_t byteAddress, uint8_t *buffer, uint32_t size) {
|
||||
// Always fail; the Xbox DVD drive doesn't support writes
|
||||
log_warning("BaseDVDDriveATADeviceDriver::Write: Unexpected write\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -138,41 +130,6 @@ uint8_t BaseDVDDriveATADeviceDriver::GetPacketCommandSize() {
|
|||
return 12;
|
||||
}
|
||||
|
||||
bool BaseDVDDriveATADeviceDriver::ValidateCommand(PacketInformation& packetInfo) {
|
||||
switch (packetInfo.cdb.opCode.u8) {
|
||||
case OpModeSense10:
|
||||
switch (packetInfo.cdb.modeSense10.pageCode) {
|
||||
case kPageCodeAuthentication:
|
||||
// TODO: is it correct to fail if the length is smaller than the page data?
|
||||
if (B2L16(packetInfo.cdb.modeSense10.length) < sizeof(XboxDVDAuthentication)) {
|
||||
packetInfo.result.aborted = true;
|
||||
packetInfo.result.incorrectLength = true;
|
||||
packetInfo.result.status = StCheckCondition;
|
||||
packetInfo.result.senseKey = SKIllegalRequest;
|
||||
packetInfo.result.additionalSenseCode = ASCInvalidFieldInCDB;
|
||||
return false;
|
||||
}
|
||||
packetInfo.transferSize = sizeof(XboxDVDAuthentication);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
case OpRequestSense:
|
||||
packetInfo.transferSize = packetInfo.cdb.requestSense.length;
|
||||
return true;
|
||||
case OpReadCapacity:
|
||||
packetInfo.transferSize = sizeof(ReadCapacityData);
|
||||
return true;
|
||||
case OpRead10:
|
||||
packetInfo.transferSize = (uint32_t)B2L16(packetInfo.cdb.read10.length) * kDVDSectorSize;
|
||||
return true;
|
||||
case OpReadDVDStructure:
|
||||
packetInfo.transferSize = kDVDSectorSize;
|
||||
return true;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,26 +33,23 @@ public:
|
|||
bool IdentifyPacketDevice(IdentifyPacketDeviceData *data) override;
|
||||
bool SecurityUnlock(uint8_t unlockData[kSectorSize]) override;
|
||||
bool SetDeviceParameters(uint8_t heads, uint8_t sectorsPerTrack) override;
|
||||
|
||||
// ----- Data access ------------------------------------------------------
|
||||
|
||||
virtual bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override = 0;
|
||||
bool Write(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override;
|
||||
|
||||
// ----- Feature sets -----------------------------------------------------
|
||||
|
||||
bool SupportsPacketCommands() override { return true; }
|
||||
bool SupportsOverlap() override { return false; }
|
||||
bool IsOverlapEnabled() override { return false; }
|
||||
|
||||
// ----- 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;
|
||||
// ----- Medium -----------------------------------------------------------
|
||||
|
||||
// ----- ATAPI ------------------------------------------------------------
|
||||
|
||||
virtual bool ValidateATAPIPacket(atapi::PacketInformation& packetInfo) override = 0;
|
||||
virtual bool ProcessATAPIPacketNonData(atapi::PacketInformation& packetInfo) override = 0;
|
||||
virtual bool ProcessATAPIPacketDataRead(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit, uint32_t *packetDataSize) override = 0;
|
||||
virtual bool ProcessATAPIPacketDataWrite(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit) override = 0;
|
||||
|
||||
bool ValidateCommand(atapi::PacketInformation& packetInfo);
|
||||
virtual bool HasMedium() override = 0;
|
||||
virtual uint32_t GetMediumCapacitySectors() override = 0;
|
||||
uint32_t GetSectorSize() override { return atapi::kDVDSectorSize; }
|
||||
|
||||
// ----- Utility functions ------------------------------------------------
|
||||
|
||||
|
@ -61,8 +58,6 @@ public:
|
|||
uint32_t CHSToLBA(uint32_t cylinder, uint8_t head, uint8_t sector) override;
|
||||
void LBAToCHS(uint32_t lbaAddress, uint16_t *cylinder, uint8_t *head, uint8_t *sector) override;
|
||||
uint8_t GetPacketCommandSize() override;
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -13,108 +13,22 @@
|
|||
|
||||
#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;
|
||||
|
||||
DummyDVDDriveATADeviceDriver::DummyDVDDriveATADeviceDriver() {
|
||||
strcpy(m_serialNumber, "1234567890");
|
||||
strcpy(m_firmwareRevision, "1.00");
|
||||
strcpy(m_modelNumber, "DUMMY DVD 12345");
|
||||
strcpy(m_serialNumber, "0123456789");
|
||||
strcpy(m_firmwareRevision, "1.0.0");
|
||||
strcpy(m_modelNumber, "vXn DDVDD0010000");
|
||||
}
|
||||
|
||||
DummyDVDDriveATADeviceDriver::~DummyDVDDriveATADeviceDriver() {
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// TODO: device-specific validation
|
||||
|
||||
// Check if the command is supported and has valid parameters.
|
||||
return ValidateCommand(packetInfo);
|
||||
}
|
||||
|
||||
bool DummyDVDDriveATADeviceDriver::ProcessATAPIPacketNonData(PacketInformation& packetInfo) {
|
||||
switch (packetInfo.cdb.opCode.u8) {
|
||||
case OpTestUnitReady:
|
||||
// Say that there is no disc in the drive
|
||||
packetInfo.result.status = StCheckCondition;
|
||||
packetInfo.result.senseKey = SKNotReady;
|
||||
packetInfo.result.additionalSenseCode = ASCMediumNotPresent;
|
||||
return true;
|
||||
default:
|
||||
log_debug("DummyDVDDriveATADeviceDriver::ProcessATAPIPacketNonData: Unimplemented operation code 0x%x\n", packetInfo.cdb.opCode.u8);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DummyDVDDriveATADeviceDriver::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("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
|
||||
packetInfo.result.status = StCheckCondition;
|
||||
packetInfo.result.senseKey = SKNotReady;
|
||||
packetInfo.result.additionalSenseCode = ASCMediumNotPresent;
|
||||
|
||||
ReadCapacityData *capData = reinterpret_cast<ReadCapacityData *>(packetDataBuffer);
|
||||
L2B32(capData->lba, 0);
|
||||
L2B32(capData->blockLength, 0);
|
||||
|
||||
*packetDataSize = sizeof(ReadCapacityData);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
log_debug("DummyDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead: Unimplemented operation code 0x%x\n", packetInfo.cdb.opCode.u8);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DummyDVDDriveATADeviceDriver::ProcessATAPIPacketDataWrite(PacketInformation& packetInfo, uint8_t *packetDataBuffer, uint16_t byteCountLimit) {
|
||||
|
||||
log_debug("DummyDVDDriveATADeviceDriver::ProcessATAPIPacketDataWrite: Unimplemented operation code 0x%x\n", packetInfo.cdb.opCode.u8);
|
||||
bool DummyDVDDriveATADeviceDriver::Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) {
|
||||
// Always fail; no media in drive
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,12 +27,14 @@ public:
|
|||
DummyDVDDriveATADeviceDriver();
|
||||
~DummyDVDDriveATADeviceDriver() override;
|
||||
|
||||
// ----- ATAPI ------------------------------------------------------------
|
||||
// ----- Data access ------------------------------------------------------
|
||||
|
||||
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;
|
||||
bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override;
|
||||
|
||||
// ----- Medium -----------------------------------------------------------
|
||||
|
||||
bool HasMedium() override { return false; }
|
||||
uint32_t GetMediumCapacitySectors() override { return 0; }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
|
||||
#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"
|
||||
#include "vixen/hw/atapi/atapi_defs.h"
|
||||
#include "vixen/hw/atapi/atapi_xbox.h"
|
||||
#include "vixen/hw/atapi/atapi_utils.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
|
@ -25,8 +25,8 @@ using namespace atapi;
|
|||
|
||||
ImageDVDDriveATADeviceDriver::ImageDVDDriveATADeviceDriver() {
|
||||
strcpy(m_serialNumber, "9876543210");
|
||||
strcpy(m_firmwareRevision, "1.00");
|
||||
strcpy(m_modelNumber, "IMAGE DVD 12345");
|
||||
strcpy(m_firmwareRevision, "1.0.0");
|
||||
strcpy(m_modelNumber, "vXn VDVDD0010000");
|
||||
}
|
||||
|
||||
ImageDVDDriveATADeviceDriver::~ImageDVDDriveATADeviceDriver() {
|
||||
|
@ -63,178 +63,40 @@ bool ImageDVDDriveATADeviceDriver::LoadImageFile(const char *imagePath, bool cop
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ImageDVDDriveATADeviceDriver::EjectMedia() {
|
||||
bool ImageDVDDriveATADeviceDriver::EjectMedium() {
|
||||
if (m_fpImage == NULL) {
|
||||
log_warning("ImageDVDDriveATADeviceDriver::EjectMedia: No media to eject\n");
|
||||
log_warning("ImageDVDDriveATADeviceDriver::EjectMedium: No medium to eject\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
log_info("ImageDVDDriveATADeviceDriver::EjectMedia: Media ejected\n");
|
||||
log_info("ImageDVDDriveATADeviceDriver::EjectMedium: Medium ejected\n");
|
||||
fclose(m_fpImage);
|
||||
m_fpImage = NULL;
|
||||
// TODO: notify media removal
|
||||
// TODO: should we 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);
|
||||
bool ImageDVDDriveATADeviceDriver::Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) {
|
||||
// TODO: maybe handle caching? Could improve performance if accessing real media on supported drives
|
||||
// Should also honor the cache flags
|
||||
// Image not loaded
|
||||
if (m_fpImage == NULL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead(PacketInformation& packetInfo, uint8_t *packetDataBuffer, uint16_t byteCountLimit, uint32_t *packetDataSize) {
|
||||
// TODO: refactor command handling
|
||||
// - make a structure similar to ATA commands
|
||||
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;
|
||||
m_transfer = true;
|
||||
log_spew("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead: Starting transfer: 0x%llx to 0x%llx\n", m_currentByte, m_lastByte);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
log_spew("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead: Transfer finished\n");
|
||||
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;
|
||||
}
|
||||
case OpReadDVDStructure:
|
||||
{
|
||||
ReadDVDStructureData *dvdData = reinterpret_cast<ReadDVDStructureData *>(packetDataBuffer);
|
||||
memset(dvdData, 0, kDVDSectorSize);
|
||||
switch (packetInfo.cdb.readDVDStructure.format) {
|
||||
case DVDFmtPhysical:
|
||||
L2B16(dvdData->dataLength, (uint16_t)sizeof(ReadDVDStructureData::physicalFormatInformation));
|
||||
// TODO: compute fields based on the image file
|
||||
dvdData->physicalFormatInformation.partVersion = 1;
|
||||
dvdData->physicalFormatInformation.bookType = BookTypeDVDROM;
|
||||
dvdData->physicalFormatInformation.maxRate = MaxRate10_08Mbps;
|
||||
dvdData->physicalFormatInformation.discSize = DiscSize120mm;
|
||||
dvdData->physicalFormatInformation.layerType = 0;
|
||||
dvdData->physicalFormatInformation.trackPath = TrackPathOTP;
|
||||
dvdData->physicalFormatInformation.numLayers = NumLayers2;
|
||||
dvdData->physicalFormatInformation.trackDensity = TrackDensity0_74umPerTrack;
|
||||
dvdData->physicalFormatInformation.linearDensity = LinearDensity0_293umPerBit;
|
||||
L2B24(dvdData->physicalFormatInformation.dataStartingSector, kStartingSectorNumberDVDROM);
|
||||
L2B24(dvdData->physicalFormatInformation.dataEndingSector, m_sectorCapacity);
|
||||
L2B24(dvdData->physicalFormatInformation.layer0EndingSector, 0);
|
||||
dvdData->physicalFormatInformation.burstCuttingArea = 0;
|
||||
|
||||
*packetDataSize = kDVDSectorSize;
|
||||
return true;
|
||||
default:
|
||||
log_debug("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead: Unimplemented format 0x%x for READ DVD STRUCTURE\n", packetInfo.cdb.readDVDStructure.format);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
default:
|
||||
log_debug("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead: Unimplemented operation code 0x%x\n", packetInfo.cdb.opCode.u8);
|
||||
// Seek address
|
||||
if (_fseeki64(m_fpImage, byteAddress, SEEK_SET)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataWrite(PacketInformation& packetInfo, uint8_t *packetDataBuffer, uint16_t byteCountLimit) {
|
||||
// Read data from image
|
||||
// TODO: handle copy-on-write
|
||||
// If copy-on-write and the sector is copied, read from copy, otherwise read from image file
|
||||
// If not copy-on-write, read from image file directly
|
||||
int lenRead = fread(buffer, 1, size, m_fpImage);
|
||||
|
||||
log_debug("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataWrite: Unimplemented operation code 0x%x\n", packetInfo.cdb.opCode.u8);
|
||||
return false;
|
||||
// Read is successful if the full size is read
|
||||
return lenRead == size;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,28 +34,22 @@ public:
|
|||
// ----- Virtual DVD image management -------------------------------------
|
||||
|
||||
bool LoadImageFile(const char *imagePath, bool copyOnWrite);
|
||||
bool EjectMedia();
|
||||
bool EjectMedium();
|
||||
|
||||
// ----- ATAPI ------------------------------------------------------------
|
||||
// ----- Data access ------------------------------------------------------
|
||||
|
||||
bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override;
|
||||
|
||||
// ----- Medium -----------------------------------------------------------
|
||||
|
||||
bool HasMedium() override { return m_fpImage != NULL; }
|
||||
uint32_t GetMediumCapacitySectors() override { return m_sectorCapacity; }
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -33,24 +33,23 @@ public:
|
|||
bool IdentifyPacketDevice(IdentifyPacketDeviceData *data) override;
|
||||
bool SecurityUnlock(uint8_t unlockData[kSectorSize]) override;
|
||||
bool SetDeviceParameters(uint8_t heads, uint8_t sectorsPerTrack) override;
|
||||
|
||||
// ----- Feature sets -----------------------------------------------------
|
||||
|
||||
bool SupportsPacketCommands() override { return false; }
|
||||
bool SupportsOverlap() override { return false; }
|
||||
bool IsOverlapEnabled() override { return false; }
|
||||
|
||||
// ----- 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;
|
||||
|
||||
// ----- ATAPI ------------------------------------------------------------
|
||||
// ----- Feature sets -----------------------------------------------------
|
||||
|
||||
bool ValidateATAPIPacket(atapi::PacketInformation& packetInfo) override { return false; }
|
||||
bool ProcessATAPIPacketNonData(atapi::PacketInformation& packetInfo) override { return false; }
|
||||
bool ProcessATAPIPacketDataRead(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit, uint32_t *packetDataSize) override { return false; }
|
||||
bool ProcessATAPIPacketDataWrite(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit) override { return false; }
|
||||
bool SupportsPacketCommands() override { return false; }
|
||||
bool SupportsOverlap() override { return false; }
|
||||
bool IsOverlapEnabled() override { return false; }
|
||||
|
||||
// ----- Medium -----------------------------------------------------------
|
||||
|
||||
bool HasMedium() override { return true; }
|
||||
virtual uint32_t GetMediumCapacitySectors() override { return m_sectorCapacity; }
|
||||
uint32_t GetSectorSize() override { return kSectorSize; }
|
||||
|
||||
// ----- Utility functions ------------------------------------------------
|
||||
|
||||
|
|
|
@ -30,9 +30,9 @@ static void padString(uint8_t *dest, const char *src, uint32_t length) {
|
|||
}
|
||||
|
||||
DummyHardDriveATADeviceDriver::DummyHardDriveATADeviceDriver() {
|
||||
strcpy(m_serialNumber, "1234567890");
|
||||
strcpy(m_firmwareRevision, "1.00");
|
||||
strcpy(m_modelNumber, "DUMMY HD 12345");
|
||||
strcpy(m_serialNumber, "0123456789");
|
||||
strcpy(m_firmwareRevision, "1.0.0");
|
||||
strcpy(m_modelNumber, "vXn DHDD0010000");
|
||||
|
||||
// Initialize with parameters for a 10 GiB hard drive
|
||||
m_numCylinders = 20480;
|
||||
|
|
|
@ -31,9 +31,9 @@ static void padString(uint8_t *dest, const char *src, uint32_t length) {
|
|||
|
||||
ImageHardDriveATADeviceDriver::ImageHardDriveATADeviceDriver() {
|
||||
// TODO: fill in with appropriate data
|
||||
strcpy(m_serialNumber, "1234567890");
|
||||
strcpy(m_firmwareRevision, "1.00");
|
||||
strcpy(m_modelNumber, "IMAGE HD 12345");
|
||||
strcpy(m_serialNumber, "9876543210");
|
||||
strcpy(m_firmwareRevision, "1.0.0");
|
||||
strcpy(m_modelNumber, "vXn VHDD0010000");
|
||||
|
||||
// Initialize an empty (invalid) disk
|
||||
m_numCylinders = 0;
|
||||
|
@ -116,12 +116,6 @@ bool ImageHardDriveATADeviceDriver::Read(uint64_t byteAddress, uint8_t *buffer,
|
|||
return false;
|
||||
}
|
||||
|
||||
// Limit size to sector size
|
||||
if (size > kSectorSize) {
|
||||
log_warning("ImageHardDriveATADeviceDriver::ReadSector: Requested size (%d) truncated\n", size);
|
||||
size = kSectorSize;
|
||||
}
|
||||
|
||||
// Seek address
|
||||
if (_fseeki64(m_fpImage, byteAddress, SEEK_SET)) {
|
||||
return false;
|
||||
|
|
81
src/core/vixen/hw/atapi/atapi_common.cpp
Normal file
81
src/core/vixen/hw/atapi/atapi_common.cpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
|
||||
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
|
||||
//
|
||||
// [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
|
||||
//
|
||||
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
|
||||
// http://www.bswd.com/sff8020i.pdf
|
||||
//
|
||||
// [s] SCSI Commands Reference Manual 100293068, Rev. J
|
||||
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification. References are prefixed by
|
||||
// the letter in brackets as listed above.
|
||||
#include "atapi_common.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace atapi {
|
||||
|
||||
PacketCommandState::DataBuffer::~DataBuffer() {
|
||||
if (m_buf != nullptr) {
|
||||
delete[] m_buf;
|
||||
}
|
||||
}
|
||||
|
||||
bool PacketCommandState::DataBuffer::Allocate(uint32_t size) {
|
||||
// Should allocate only once
|
||||
assert(m_buf == nullptr);
|
||||
|
||||
m_buf = new uint8_t[size];
|
||||
if (m_buf == nullptr) {
|
||||
return false;
|
||||
}
|
||||
m_size = 0;
|
||||
m_cap = size;
|
||||
Clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t PacketCommandState::DataBuffer::Read(void *dst, uint32_t length) {
|
||||
assert(m_buf != nullptr);
|
||||
|
||||
// Truncate to data length
|
||||
if (length + m_readPos > m_size) {
|
||||
length = m_size - m_readPos;
|
||||
}
|
||||
memcpy(dst, m_buf + m_readPos, length);
|
||||
m_readPos += length;
|
||||
return length;
|
||||
}
|
||||
|
||||
uint32_t PacketCommandState::DataBuffer::Write(void *src, uint32_t length) {
|
||||
assert(m_buf != nullptr);
|
||||
|
||||
// Truncate to allocation length
|
||||
if (length + m_writePos > m_cap) {
|
||||
length = m_cap - m_writePos;
|
||||
}
|
||||
memcpy(m_buf, src, length);
|
||||
m_size = length;
|
||||
return length;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement a subset of the ATAPI Command set used by the
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
|
@ -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
|
||||
//
|
||||
|
@ -33,18 +36,67 @@ namespace vixen {
|
|||
namespace hw {
|
||||
namespace atapi {
|
||||
|
||||
// ----- Packet Information ---------------------------------------------------
|
||||
// ----- Packet Command State -------------------------------------------------
|
||||
|
||||
// Keeps the state of a packet command execution
|
||||
struct PacketCommandState {
|
||||
struct InputParameters {
|
||||
// Whether the operation is to be overlapped
|
||||
bool overlapped;
|
||||
|
||||
// Whether to execute a DMA (true) or PIO (false) transfer
|
||||
bool dmaTransfer;
|
||||
|
||||
// The operation tag
|
||||
uint8_t tag;
|
||||
|
||||
// The maximum number of bytes to transfer in a single DRQ block
|
||||
uint16_t byteCountLimit;
|
||||
|
||||
// The selected device (DEV)
|
||||
uint8_t selectedDevice;
|
||||
} input;
|
||||
|
||||
// Information about a packet command
|
||||
struct PacketInformation {
|
||||
// The command descriptor block
|
||||
CommandDescriptorBlock cdb;
|
||||
|
||||
// The operation type
|
||||
PacketOperationType opType;
|
||||
struct DataBuffer {
|
||||
~DataBuffer();
|
||||
|
||||
// The size of the data to be transferred for this packet command
|
||||
uint32_t transferSize;
|
||||
// Allocates a buffer for data transfer
|
||||
bool Allocate(uint32_t size);
|
||||
|
||||
// Copy data into the destination buffer, returning the number of bytes read
|
||||
uint32_t Read(void *dst, uint32_t length);
|
||||
|
||||
// Copy data from the source buffer, returning the number of bytes written
|
||||
uint32_t Write(void *src, uint32_t length);
|
||||
|
||||
// Clears the buffer, resetting the read and write pointers
|
||||
void Clear() { m_readPos = m_writePos = m_size = 0; }
|
||||
|
||||
// Determines if the buffer's data has been fully read from
|
||||
bool IsReadFinished() { return m_readPos >= m_size; }
|
||||
|
||||
// Determines if the buffer's data has been fully written to
|
||||
bool IsWriteFinished() { return m_writePos >= m_cap; }
|
||||
|
||||
private:
|
||||
// The data buffer to be used with transfer operations
|
||||
uint8_t *m_buf = nullptr;
|
||||
|
||||
// The size of the data buffer, i.e. the number of valid bytes written to the buffer
|
||||
uint32_t m_size;
|
||||
|
||||
// The capacity of the data buffer, i.e. the length of the buffer
|
||||
uint32_t m_cap;
|
||||
|
||||
// The position of the writer
|
||||
uint32_t m_writePos;
|
||||
|
||||
// The position of the reader
|
||||
uint32_t m_readPos;
|
||||
} dataBuffer;
|
||||
|
||||
// Execution result data, filled in by the driver once the command is processed
|
||||
struct ExecutionResult {
|
|
@ -1,7 +1,7 @@
|
|||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement a subset of the ATAPI Command set used by the
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
|
@ -127,7 +127,7 @@ union CommandDescriptorBlock {
|
|||
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 allocLength[2]; // byte 7-8 Allocation Length
|
||||
uint8_t control; // byte 9 Control
|
||||
} modeSense10;
|
||||
|
||||
|
@ -144,7 +144,7 @@ union CommandDescriptorBlock {
|
|||
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 transferLength[2]; // byte 7-8 Transfer length
|
||||
uint8_t control; // byte 9 Control
|
||||
} read10;
|
||||
|
||||
|
@ -164,7 +164,7 @@ union CommandDescriptorBlock {
|
|||
uint8_t address; // byte 2-5 Address
|
||||
uint8_t layerNumber; // byte 6 Layer number
|
||||
uint8_t format; // byte 7 Format
|
||||
uint8_t length[2]; // byte 8-9 Allocation Length
|
||||
uint8_t allocLength[2]; // byte 8-9 Allocation Length
|
||||
uint8_t _reserved2 : 6; // byte 10 [5:0] Reserved
|
||||
uint8_t authGrantID : 2; // byte 10 [7:6] (AGID) Authenticaton Grant ID (used with formats 2, 6 and 7 when address is 0)
|
||||
uint8_t control; // byte 11 Control
|
||||
|
@ -175,7 +175,7 @@ union CommandDescriptorBlock {
|
|||
struct RequestSense {
|
||||
OperationCode opCode; // byte 0 Operation Code (0x03)
|
||||
uint8_t _reserved1[3]; // byte 1-3 Reserved
|
||||
uint8_t length; // byte 4 Allocation Length
|
||||
uint8_t allocLength; // byte 4 Allocation Length
|
||||
uint8_t control; // byte 5 Control
|
||||
} requestSense;
|
||||
|
||||
|
@ -420,6 +420,7 @@ enum AdditionalSenseCode : uint16_t {
|
|||
ASCNone = 0x0000, // No additional sense information
|
||||
ASCInvalidFieldInCDB = 0x2400, // Invalid field in CDB
|
||||
ASCMediumNotPresent = 0x3A00, // Medium not present
|
||||
ASCEndOfMediumReached = 0x3B0F, // End of medium reached
|
||||
};
|
||||
|
||||
}
|
|
@ -1,7 +1,31 @@
|
|||
// ATA/ATAPI-4 emulation for the Original Xbox
|
||||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// Utility functions for dealing with ATAPI / SCSI data structures.
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
|
||||
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
|
||||
//
|
||||
// [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
|
||||
//
|
||||
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
|
||||
// http://www.bswd.com/sff8020i.pdf
|
||||
//
|
||||
// [s] SCSI Commands Reference Manual 100293068, Rev. J
|
||||
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification. References are prefixed by
|
||||
// the letter in brackets as listed above.
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
@ -39,42 +63,42 @@ inline uint64_t B2L64(uint8_t bytes[8]) {
|
|||
|
||||
// Converts a 16-bit unsigned integer from little-endian to big-endian.
|
||||
inline void L2B16(uint8_t bytes[2], uint16_t val) {
|
||||
bytes[0] = val >> 8;
|
||||
bytes[1] = val;
|
||||
bytes[0] = (uint8_t)(val >> 8);
|
||||
bytes[1] = (uint8_t)val;
|
||||
}
|
||||
|
||||
// Converts a 24-bit unsigned integer from little-endian to big-endian.
|
||||
inline void L2B24(uint8_t bytes[3], uint32_t val) {
|
||||
bytes[0] = val >> 16;
|
||||
bytes[1] = val >> 8;
|
||||
bytes[2] = val;
|
||||
bytes[0] = (uint8_t)(val >> 16);
|
||||
bytes[1] = (uint8_t)(val >> 8);
|
||||
bytes[2] = (uint8_t)val;
|
||||
}
|
||||
|
||||
// Converts a 24-bit unsigned integer split into low 16-bit and high 8-bit parts from little-endian to big-endian.
|
||||
inline void L2B24S(uint8_t *high, uint8_t low[2], uint32_t val) {
|
||||
*high = val >> 16;
|
||||
low[0] = val >> 8;
|
||||
low[1] = val;
|
||||
*high = (uint8_t)(val >> 16);
|
||||
low[0] = (uint8_t)(val >> 8);
|
||||
low[1] = (uint8_t)val;
|
||||
}
|
||||
|
||||
// Converts a 32-bit unsigned integer from little-endian to big-endian.
|
||||
inline void L2B32(uint8_t bytes[4], uint32_t val) {
|
||||
bytes[0] = val >> 24;
|
||||
bytes[1] = val >> 16;
|
||||
bytes[2] = val >> 8;
|
||||
bytes[3] = val;
|
||||
bytes[0] = (uint8_t)(val >> 24);
|
||||
bytes[1] = (uint8_t)(val >> 16);
|
||||
bytes[2] = (uint8_t)(val >> 8);
|
||||
bytes[3] = (uint8_t)val;
|
||||
}
|
||||
|
||||
// Converts a 64-bit unsigned integer from little-endian to big-endian.
|
||||
inline void L2B64(uint8_t bytes[8], uint64_t val) {
|
||||
bytes[0] = val >> 56L;
|
||||
bytes[1] = val >> 48L;
|
||||
bytes[2] = val >> 40L;
|
||||
bytes[3] = val >> 32L;
|
||||
bytes[4] = val >> 24L;
|
||||
bytes[5] = val >> 16L;
|
||||
bytes[6] = val >> 8L;
|
||||
bytes[7] = val;
|
||||
bytes[0] = (uint8_t)(val >> 56L);
|
||||
bytes[1] = (uint8_t)(val >> 48L);
|
||||
bytes[2] = (uint8_t)(val >> 40L);
|
||||
bytes[3] = (uint8_t)(val >> 32L);
|
||||
bytes[4] = (uint8_t)(val >> 24L);
|
||||
bytes[5] = (uint8_t)(val >> 16L);
|
||||
bytes[6] = (uint8_t)(val >> 8L);
|
||||
bytes[7] = (uint8_t)val;
|
||||
}
|
||||
|
||||
}
|
|
@ -19,11 +19,11 @@ namespace atapi {
|
|||
|
||||
// SCSI MODE SENSE and MODE SELECT page code for the security data.
|
||||
// Contains the XboxDVDAuthentication struct.
|
||||
// http://xboxdevwiki.net/DVD_Drive
|
||||
// [w] http://xboxdevwiki.net/DVD_Drive
|
||||
const uint8_t kPageCodeAuthentication = 0x3E;
|
||||
|
||||
// The Xbox DVD authentication page data.
|
||||
// https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/blob/e452d56991c7dce655511c5529f4cf1a6fe98e42/import/OpenXDK/include/xboxkrnl/xboxkrnl.h#L2494
|
||||
// [c] https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/blob/e452d56991c7dce655511c5529f4cf1a6fe98e42/import/OpenXDK/include/xboxkrnl/xboxkrnl.h#L2494
|
||||
struct XboxDVDAuthentication {
|
||||
uint8_t Unknown[2];
|
||||
uint8_t PartitionArea;
|
50
src/core/vixen/hw/atapi/cmds/atapi_command.cpp
Normal file
50
src/core/vixen/hw/atapi/cmds/atapi_command.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
|
||||
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
|
||||
//
|
||||
// [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
|
||||
//
|
||||
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
|
||||
// http://www.bswd.com/sff8020i.pdf
|
||||
//
|
||||
// [s] SCSI Commands Reference Manual 100293068, Rev. J
|
||||
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification. References are prefixed by
|
||||
// the letter in brackets as listed above.
|
||||
#include "atapi_command.h"
|
||||
|
||||
#include "vixen/log.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace atapi {
|
||||
namespace cmd {
|
||||
|
||||
IATAPICommand::IATAPICommand(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver)
|
||||
: m_packetCmdState(packetCmdState)
|
||||
, m_driver(driver)
|
||||
{
|
||||
}
|
||||
|
||||
IATAPICommand::~IATAPICommand() {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
95
src/core/vixen/hw/atapi/cmds/atapi_command.h
Normal file
95
src/core/vixen/hw/atapi/cmds/atapi_command.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
|
||||
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
|
||||
//
|
||||
// [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
|
||||
//
|
||||
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
|
||||
// http://www.bswd.com/sff8020i.pdf
|
||||
//
|
||||
// [s] SCSI Commands Reference Manual 100293068, Rev. J
|
||||
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification. References are prefixed by
|
||||
// the letter in brackets as listed above.
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "../atapi_common.h"
|
||||
#include "../atapi_utils.h"
|
||||
#include "../atapi_xbox.h"
|
||||
#include "vixen/hw/ata/drvs/ata_device_driver.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace atapi {
|
||||
namespace cmd {
|
||||
|
||||
/*!
|
||||
* Interface for ATAPI commands.
|
||||
*
|
||||
* Classes that derive this interface provide base implementations for ATAPI
|
||||
* protocols, which handle the basic flow of the packet command execution.
|
||||
*/
|
||||
class IATAPICommand {
|
||||
public:
|
||||
IATAPICommand(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver);
|
||||
virtual ~IATAPICommand();
|
||||
|
||||
/*!
|
||||
* Validates input parameters and allocates a data transfer buffer if
|
||||
* required by the command. If the command transfers data to the host,
|
||||
* the buffer is pre-filled with the necessary data.
|
||||
*
|
||||
* Status (including sense key and additional sense code) is updated in
|
||||
* the packet command state.
|
||||
*
|
||||
* Returns true if the packet data has been successfully validated and
|
||||
* the command is ready to be executed or to receive data.
|
||||
*/
|
||||
virtual bool Prepare() = 0;
|
||||
|
||||
/*!
|
||||
* Executes the command with the provided state.
|
||||
*/
|
||||
virtual bool Execute() = 0;
|
||||
|
||||
/*!
|
||||
* Determines if the data transfer has finished.
|
||||
*/
|
||||
virtual bool IsTransferFinished() = 0;
|
||||
|
||||
/*!
|
||||
* Retrieves the operation type for this command.
|
||||
*/
|
||||
virtual PacketOperationType GetOperationType() = 0;
|
||||
|
||||
/*!
|
||||
* Defines the factory function type used to build a factory table.
|
||||
*/
|
||||
typedef IATAPICommand* (*Factory)(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver);
|
||||
|
||||
protected:
|
||||
PacketCommandState& m_packetCmdState;
|
||||
ata::IATADeviceDriver *m_driver;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
77
src/core/vixen/hw/atapi/cmds/cmd_mode_sense_10.cpp
Normal file
77
src/core/vixen/hw/atapi/cmds/cmd_mode_sense_10.cpp
Normal file
|
@ -0,0 +1,77 @@
|
|||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
|
||||
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
|
||||
//
|
||||
// [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
|
||||
//
|
||||
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
|
||||
// http://www.bswd.com/sff8020i.pdf
|
||||
//
|
||||
// [s] SCSI Commands Reference Manual 100293068, Rev. J
|
||||
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification. References are prefixed by
|
||||
// the letter in brackets as listed above.
|
||||
#include "cmd_mode_sense_10.h"
|
||||
|
||||
#include "vixen/log.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace atapi {
|
||||
namespace cmd {
|
||||
|
||||
ModeSense10::ModeSense10(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver)
|
||||
: ATAPIDataInCommand(packetCmdState, driver)
|
||||
{
|
||||
}
|
||||
|
||||
ModeSense10::~ModeSense10() {
|
||||
}
|
||||
|
||||
bool ModeSense10::BeginTransfer() {
|
||||
auto& cdb = m_packetCmdState.cdb.modeSense10;
|
||||
switch (cdb.pageCode) {
|
||||
case kPageCodeAuthentication:
|
||||
{
|
||||
// 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 = { 0 };
|
||||
dvdAuth.CDFValid = 1;
|
||||
dvdAuth.PartitionArea = 1;
|
||||
dvdAuth.Authentication = 1;
|
||||
|
||||
m_packetCmdState.dataBuffer.Write(&dvdAuth, sizeof(dvdAuth));
|
||||
EndTransfer();
|
||||
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
log_warning("ModeSense10::Execute: Unimplemented page code 0x%x\n", cdb.pageCode);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ModeSense10::GetAllocationLength(CommandDescriptorBlock *cdb) {
|
||||
return B2L16(cdb->modeSense10.allocLength);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
62
src/core/vixen/hw/atapi/cmds/cmd_mode_sense_10.h
Normal file
62
src/core/vixen/hw/atapi/cmds/cmd_mode_sense_10.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
|
||||
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
|
||||
//
|
||||
// [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
|
||||
//
|
||||
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
|
||||
// http://www.bswd.com/sff8020i.pdf
|
||||
//
|
||||
// [s] SCSI Commands Reference Manual 100293068, Rev. J
|
||||
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification. References are prefixed by
|
||||
// the letter in brackets as listed above.
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "proto_data_in.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace atapi {
|
||||
namespace cmd {
|
||||
|
||||
/*!
|
||||
* Implements the MODE SENSE(10) command (0x5A) [p 6.10].
|
||||
*/
|
||||
class ModeSense10 : public ATAPIDataInCommand {
|
||||
public:
|
||||
ModeSense10(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver);
|
||||
virtual ~ModeSense10();
|
||||
|
||||
bool BeginTransfer() override;
|
||||
|
||||
// This command only transfer one block; Execute() will never be invoked
|
||||
bool Execute() override { return false; }
|
||||
|
||||
static IATAPICommand *Factory(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) { return new ModeSense10(packetCmdState, driver); }
|
||||
|
||||
protected:
|
||||
uint32_t GetAllocationLength(CommandDescriptorBlock *cdb) override;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
132
src/core/vixen/hw/atapi/cmds/cmd_read_10.cpp
Normal file
132
src/core/vixen/hw/atapi/cmds/cmd_read_10.cpp
Normal file
|
@ -0,0 +1,132 @@
|
|||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
|
||||
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
|
||||
//
|
||||
// [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
|
||||
//
|
||||
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
|
||||
// http://www.bswd.com/sff8020i.pdf
|
||||
//
|
||||
// [s] SCSI Commands Reference Manual 100293068, Rev. J
|
||||
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification. References are prefixed by
|
||||
// the letter in brackets as listed above.
|
||||
#include "cmd_read_10.h"
|
||||
|
||||
#include "vixen/log.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace atapi {
|
||||
namespace cmd {
|
||||
|
||||
Read10::Read10(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver)
|
||||
: ATAPIDataInCommand(packetCmdState, driver)
|
||||
{
|
||||
}
|
||||
|
||||
Read10::~Read10() {
|
||||
if (m_buffer != nullptr) {
|
||||
delete[] m_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
bool Read10::BeginTransfer() {
|
||||
auto& cdb = m_packetCmdState.cdb.read10;
|
||||
if (!m_driver->HasMedium()) {
|
||||
// There is no medium in the drive
|
||||
m_packetCmdState.result.status = StCheckCondition;
|
||||
m_packetCmdState.result.senseKey = SKNotReady;
|
||||
m_packetCmdState.result.additionalSenseCode = ASCMediumNotPresent;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t lba = B2L32(cdb.lba);
|
||||
uint16_t transferLength = B2L16(cdb.transferLength);
|
||||
uint32_t transferLengthBytes = (uint32_t)transferLength * m_driver->GetSectorSize();
|
||||
|
||||
m_transferLength = transferLengthBytes;
|
||||
if (m_transferLength > m_packetCmdState.input.byteCountLimit) {
|
||||
m_transferLength = m_packetCmdState.input.byteCountLimit;
|
||||
}
|
||||
|
||||
// Allocate buffer and setup transfer parameters
|
||||
m_currentByte = lba * m_driver->GetSectorSize();
|
||||
m_lastByte = m_currentByte + transferLengthBytes;
|
||||
m_buffer = new uint8_t[m_transferLength];
|
||||
|
||||
log_spew("Read10::BeginTransfer: Starting transfer: 0x%llx to 0x%llx\n", m_currentByte, m_lastByte);
|
||||
|
||||
// Read from media
|
||||
return Execute();
|
||||
}
|
||||
|
||||
bool Read10::Execute() {
|
||||
uint32_t readLen = m_lastByte - m_currentByte;
|
||||
if (readLen > m_transferLength) {
|
||||
readLen = m_transferLength;
|
||||
}
|
||||
|
||||
if (!m_driver->HasMedium()) {
|
||||
// No medium in drive
|
||||
m_packetCmdState.result.status = StCheckCondition;
|
||||
m_packetCmdState.result.senseKey = SKIllegalRequest;
|
||||
m_packetCmdState.result.additionalSenseCode = ASCMediumNotPresent;
|
||||
log_spew("Read10::Execute: Medium not present\n");
|
||||
EndTransfer();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read from the device
|
||||
// TODO: maybe handle caching? Could improve performance if accessing real media on supported drives
|
||||
// Should also honor the cache flags
|
||||
bool successful = m_driver->Read(m_currentByte, m_buffer, readLen);
|
||||
|
||||
if (!successful) {
|
||||
// Reached the end of the medium
|
||||
m_packetCmdState.result.status = StCheckCondition;
|
||||
m_packetCmdState.result.senseKey = SKNoSense;
|
||||
m_packetCmdState.result.additionalSenseCode = ASCEndOfMediumReached;
|
||||
m_packetCmdState.result.endOfMedium = true;
|
||||
log_spew("Read10::Execute: Reached end of medium\n");
|
||||
EndTransfer();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update position and check if the transfer ended
|
||||
m_currentByte += readLen;
|
||||
if (m_currentByte >= m_lastByte) {
|
||||
log_spew("Read10::Execute: Transfer finished\n");
|
||||
EndTransfer();
|
||||
}
|
||||
|
||||
// Write to the transfer buffer
|
||||
m_packetCmdState.dataBuffer.Clear();
|
||||
m_packetCmdState.dataBuffer.Write(m_buffer, readLen);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t Read10::GetAllocationLength(CommandDescriptorBlock *cdb) {
|
||||
return B2L16(cdb->read10.transferLength) * m_driver->GetSectorSize();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
73
src/core/vixen/hw/atapi/cmds/cmd_read_10.h
Normal file
73
src/core/vixen/hw/atapi/cmds/cmd_read_10.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
|
||||
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
|
||||
//
|
||||
// [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
|
||||
//
|
||||
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
|
||||
// http://www.bswd.com/sff8020i.pdf
|
||||
//
|
||||
// [s] SCSI Commands Reference Manual 100293068, Rev. J
|
||||
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification. References are prefixed by
|
||||
// the letter in brackets as listed above.
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "proto_data_in.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace atapi {
|
||||
namespace cmd {
|
||||
|
||||
/*!
|
||||
* Implements the READ(10) command (0x28) [b 5.11].
|
||||
*/
|
||||
class Read10 : public ATAPIDataInCommand {
|
||||
public:
|
||||
Read10(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver);
|
||||
virtual ~Read10();
|
||||
|
||||
bool BeginTransfer() override;
|
||||
bool Execute() override;
|
||||
|
||||
static IATAPICommand *Factory(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) { return new Read10(packetCmdState, driver); }
|
||||
|
||||
protected:
|
||||
uint32_t GetAllocationLength(CommandDescriptorBlock *cdb) override;
|
||||
|
||||
private:
|
||||
// Maximum number of bytes to transfer in a single read operation
|
||||
uint32_t m_transferLength;
|
||||
|
||||
// Next starting byte to read
|
||||
uint64_t m_currentByte;
|
||||
|
||||
// Last byte to read (exclusive)
|
||||
uint64_t m_lastByte;
|
||||
|
||||
// Read buffer
|
||||
uint8_t *m_buffer;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
76
src/core/vixen/hw/atapi/cmds/cmd_read_capacity.cpp
Normal file
76
src/core/vixen/hw/atapi/cmds/cmd_read_capacity.cpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
|
||||
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
|
||||
//
|
||||
// [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
|
||||
//
|
||||
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
|
||||
// http://www.bswd.com/sff8020i.pdf
|
||||
//
|
||||
// [s] SCSI Commands Reference Manual 100293068, Rev. J
|
||||
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification. References are prefixed by
|
||||
// the letter in brackets as listed above.
|
||||
#include "cmd_read_capacity.h"
|
||||
|
||||
#include "vixen/log.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace atapi {
|
||||
namespace cmd {
|
||||
|
||||
ReadCapacity::ReadCapacity(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver)
|
||||
: ATAPIDataInCommand(packetCmdState, driver)
|
||||
{
|
||||
}
|
||||
|
||||
ReadCapacity::~ReadCapacity() {
|
||||
}
|
||||
|
||||
bool ReadCapacity::BeginTransfer() {
|
||||
auto& cdb = m_packetCmdState.cdb.readCapacity;
|
||||
ReadCapacityData capData = { 0 };
|
||||
|
||||
if (m_driver->HasMedium()) {
|
||||
L2B32(capData.lba, m_driver->GetMediumCapacitySectors());
|
||||
L2B32(capData.blockLength, m_driver->GetSectorSize());
|
||||
}
|
||||
else {
|
||||
// Say that there is no disc in the drive
|
||||
m_packetCmdState.result.status = StCheckCondition;
|
||||
m_packetCmdState.result.senseKey = SKNotReady;
|
||||
m_packetCmdState.result.additionalSenseCode = ASCMediumNotPresent;
|
||||
|
||||
L2B32(capData.lba, 0);
|
||||
L2B32(capData.blockLength, 0);
|
||||
}
|
||||
m_packetCmdState.dataBuffer.Write(&capData, sizeof(capData));
|
||||
EndTransfer();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t ReadCapacity::GetAllocationLength(CommandDescriptorBlock *cdb) {
|
||||
return sizeof(ReadCapacityData);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
62
src/core/vixen/hw/atapi/cmds/cmd_read_capacity.h
Normal file
62
src/core/vixen/hw/atapi/cmds/cmd_read_capacity.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
|
||||
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
|
||||
//
|
||||
// [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
|
||||
//
|
||||
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
|
||||
// http://www.bswd.com/sff8020i.pdf
|
||||
//
|
||||
// [s] SCSI Commands Reference Manual 100293068, Rev. J
|
||||
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification. References are prefixed by
|
||||
// the letter in brackets as listed above.
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "proto_data_in.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace atapi {
|
||||
namespace cmd {
|
||||
|
||||
/*!
|
||||
* Implements the READ CAPACITY command (0x25) [m 5.16].
|
||||
*/
|
||||
class ReadCapacity : public ATAPIDataInCommand {
|
||||
public:
|
||||
ReadCapacity(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver);
|
||||
virtual ~ReadCapacity();
|
||||
|
||||
bool BeginTransfer() override;
|
||||
|
||||
// This command only transfer one block; Execute() will never be invoked
|
||||
bool Execute() override { return false; }
|
||||
|
||||
static IATAPICommand *Factory(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) { return new ReadCapacity(packetCmdState, driver); }
|
||||
|
||||
protected:
|
||||
uint32_t GetAllocationLength(CommandDescriptorBlock *cdb) override;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
86
src/core/vixen/hw/atapi/cmds/cmd_read_dvd_structure.cpp
Normal file
86
src/core/vixen/hw/atapi/cmds/cmd_read_dvd_structure.cpp
Normal file
|
@ -0,0 +1,86 @@
|
|||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
|
||||
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
|
||||
//
|
||||
// [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
|
||||
//
|
||||
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
|
||||
// http://www.bswd.com/sff8020i.pdf
|
||||
//
|
||||
// [s] SCSI Commands Reference Manual 100293068, Rev. J
|
||||
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification. References are prefixed by
|
||||
// the letter in brackets as listed above.
|
||||
#include "cmd_read_dvd_structure.h"
|
||||
|
||||
#include "vixen/log.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace atapi {
|
||||
namespace cmd {
|
||||
|
||||
ReadDVDStructure::ReadDVDStructure(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver)
|
||||
: ATAPIDataInCommand(packetCmdState, driver)
|
||||
{
|
||||
}
|
||||
|
||||
ReadDVDStructure::~ReadDVDStructure() {
|
||||
}
|
||||
|
||||
bool ReadDVDStructure::BeginTransfer() {
|
||||
auto& cdb = m_packetCmdState.cdb.readDVDStructure;
|
||||
ReadDVDStructureData dvdData = { 0 };
|
||||
switch (cdb.format) {
|
||||
case DVDFmtPhysical:
|
||||
L2B16(dvdData.dataLength, (uint16_t)sizeof(ReadDVDStructureData::physicalFormatInformation));
|
||||
|
||||
// TODO: Compute fields based on the data reported by the driver
|
||||
// Or perhaps let the driver fill it in?
|
||||
dvdData.physicalFormatInformation.partVersion = 1;
|
||||
dvdData.physicalFormatInformation.bookType = BookTypeDVDROM;
|
||||
dvdData.physicalFormatInformation.maxRate = MaxRate10_08Mbps;
|
||||
dvdData.physicalFormatInformation.discSize = DiscSize120mm;
|
||||
dvdData.physicalFormatInformation.layerType = 0;
|
||||
dvdData.physicalFormatInformation.trackPath = TrackPathOTP;
|
||||
dvdData.physicalFormatInformation.numLayers = NumLayers2;
|
||||
dvdData.physicalFormatInformation.trackDensity = TrackDensity0_74umPerTrack;
|
||||
dvdData.physicalFormatInformation.linearDensity = LinearDensity0_293umPerBit;
|
||||
L2B24(dvdData.physicalFormatInformation.dataStartingSector, kStartingSectorNumberDVDROM);
|
||||
L2B24(dvdData.physicalFormatInformation.dataEndingSector, m_driver->GetMediumCapacitySectors());
|
||||
L2B24(dvdData.physicalFormatInformation.layer0EndingSector, 0);
|
||||
dvdData.physicalFormatInformation.burstCuttingArea = 0;
|
||||
|
||||
m_packetCmdState.dataBuffer.Write(&dvdData, sizeof(dvdData));
|
||||
EndTransfer();
|
||||
|
||||
return true;
|
||||
default:
|
||||
log_debug("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead: Unimplemented format 0x%x for READ DVD STRUCTURE\n", cdb.format);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ReadDVDStructure::GetAllocationLength(CommandDescriptorBlock *cdb) {
|
||||
return B2L16(cdb->readDVDStructure.allocLength);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
62
src/core/vixen/hw/atapi/cmds/cmd_read_dvd_structure.h
Normal file
62
src/core/vixen/hw/atapi/cmds/cmd_read_dvd_structure.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
|
||||
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
|
||||
//
|
||||
// [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
|
||||
//
|
||||
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
|
||||
// http://www.bswd.com/sff8020i.pdf
|
||||
//
|
||||
// [s] SCSI Commands Reference Manual 100293068, Rev. J
|
||||
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification. References are prefixed by
|
||||
// the letter in brackets as listed above.
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "proto_data_in.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace atapi {
|
||||
namespace cmd {
|
||||
|
||||
/*!
|
||||
* Implements the READ DVD STRUCTURE command (0xAD) [m 5.20].
|
||||
*/
|
||||
class ReadDVDStructure : public ATAPIDataInCommand {
|
||||
public:
|
||||
ReadDVDStructure(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver);
|
||||
virtual ~ReadDVDStructure();
|
||||
|
||||
bool BeginTransfer() override;
|
||||
|
||||
// This command only transfer one block; Execute() will never be invoked
|
||||
bool Execute() override { return false; }
|
||||
|
||||
static IATAPICommand *Factory(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) { return new ReadDVDStructure(packetCmdState, driver); }
|
||||
|
||||
protected:
|
||||
uint32_t GetAllocationLength(CommandDescriptorBlock *cdb) override;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
65
src/core/vixen/hw/atapi/cmds/cmd_test_unit_ready.cpp
Normal file
65
src/core/vixen/hw/atapi/cmds/cmd_test_unit_ready.cpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
|
||||
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
|
||||
//
|
||||
// [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
|
||||
//
|
||||
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
|
||||
// http://www.bswd.com/sff8020i.pdf
|
||||
//
|
||||
// [s] SCSI Commands Reference Manual 100293068, Rev. J
|
||||
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification. References are prefixed by
|
||||
// the letter in brackets as listed above.
|
||||
#include "cmd_test_unit_ready.h"
|
||||
|
||||
#include "vixen/log.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace atapi {
|
||||
namespace cmd {
|
||||
|
||||
TestUnitReady::TestUnitReady(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver)
|
||||
: ATAPINonDataCommand(packetCmdState, driver)
|
||||
{
|
||||
}
|
||||
|
||||
TestUnitReady::~TestUnitReady() {
|
||||
}
|
||||
|
||||
bool TestUnitReady::Prepare() {
|
||||
// Nothing to prepare or validate
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestUnitReady::Execute() {
|
||||
// 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 (!m_driver->HasMedium()) {
|
||||
m_packetCmdState.result.status = StCheckCondition;
|
||||
m_packetCmdState.result.senseKey = SKNotReady;
|
||||
m_packetCmdState.result.additionalSenseCode = ASCMediumNotPresent;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
57
src/core/vixen/hw/atapi/cmds/cmd_test_unit_ready.h
Normal file
57
src/core/vixen/hw/atapi/cmds/cmd_test_unit_ready.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
|
||||
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
|
||||
//
|
||||
// [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
|
||||
//
|
||||
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
|
||||
// http://www.bswd.com/sff8020i.pdf
|
||||
//
|
||||
// [s] SCSI Commands Reference Manual 100293068, Rev. J
|
||||
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification. References are prefixed by
|
||||
// the letter in brackets as listed above.
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "proto_nondata.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace atapi {
|
||||
namespace cmd {
|
||||
|
||||
/*!
|
||||
* Implements the TEST UNIT READY command (0x00) [p 6.33].
|
||||
*/
|
||||
class TestUnitReady : public ATAPINonDataCommand {
|
||||
public:
|
||||
TestUnitReady(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver);
|
||||
virtual ~TestUnitReady();
|
||||
|
||||
bool Prepare() override;
|
||||
bool Execute() override;
|
||||
|
||||
static IATAPICommand *Factory(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) { return new TestUnitReady(packetCmdState, driver); }
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
64
src/core/vixen/hw/atapi/cmds/proto_data_in.cpp
Normal file
64
src/core/vixen/hw/atapi/cmds/proto_data_in.cpp
Normal file
|
@ -0,0 +1,64 @@
|
|||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
|
||||
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
|
||||
//
|
||||
// [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
|
||||
//
|
||||
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
|
||||
// http://www.bswd.com/sff8020i.pdf
|
||||
//
|
||||
// [s] SCSI Commands Reference Manual 100293068, Rev. J
|
||||
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification. References are prefixed by
|
||||
// the letter in brackets as listed above.
|
||||
#include "proto_data_in.h"
|
||||
|
||||
#include "vixen/log.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace atapi {
|
||||
namespace cmd {
|
||||
|
||||
ATAPIDataInCommand::ATAPIDataInCommand(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver)
|
||||
: IATAPICommand(packetCmdState, driver)
|
||||
{
|
||||
}
|
||||
|
||||
ATAPIDataInCommand::~ATAPIDataInCommand() {
|
||||
}
|
||||
|
||||
bool ATAPIDataInCommand::Prepare() {
|
||||
// Get allocation length and allocate buffer
|
||||
uint32_t allocLength = GetAllocationLength(&m_packetCmdState.cdb);
|
||||
if (allocLength > m_packetCmdState.input.byteCountLimit) {
|
||||
allocLength = m_packetCmdState.input.byteCountLimit;
|
||||
}
|
||||
if (!m_packetCmdState.dataBuffer.Allocate(allocLength)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize buffer with data.
|
||||
// May access the device if needed.
|
||||
return BeginTransfer();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
87
src/core/vixen/hw/atapi/cmds/proto_data_in.h
Normal file
87
src/core/vixen/hw/atapi/cmds/proto_data_in.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
|
||||
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
|
||||
//
|
||||
// [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
|
||||
//
|
||||
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
|
||||
// http://www.bswd.com/sff8020i.pdf
|
||||
//
|
||||
// [s] SCSI Commands Reference Manual 100293068, Rev. J
|
||||
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification. References are prefixed by
|
||||
// the letter in brackets as listed above.
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "atapi_command.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace atapi {
|
||||
namespace cmd {
|
||||
|
||||
/*!
|
||||
* Base class for all ATAPI commands that transfer data to the host.
|
||||
*/
|
||||
class ATAPIDataInCommand : public IATAPICommand {
|
||||
public:
|
||||
ATAPIDataInCommand(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver);
|
||||
virtual ~ATAPIDataInCommand();
|
||||
|
||||
bool Prepare() override;
|
||||
|
||||
/*!
|
||||
* Reads data into the buffer.
|
||||
*
|
||||
* Returns true if the data retrieval succeeded, or false if there was any error.
|
||||
*/
|
||||
virtual bool Execute() override = 0;
|
||||
|
||||
PacketOperationType GetOperationType() override { return PktOpDataIn; }
|
||||
|
||||
bool IsTransferFinished() override { return m_transferFinished; }
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* Retrieves the allocation length from the CDB. Each command has its own
|
||||
* CDB structure, and the allocation length is not necessarily in the same
|
||||
* location or has the same size.
|
||||
*/
|
||||
virtual uint32_t GetAllocationLength(CommandDescriptorBlock *cdb) = 0;
|
||||
|
||||
/*!
|
||||
* Initializes the data transfer.
|
||||
*/
|
||||
virtual bool BeginTransfer() = 0;
|
||||
|
||||
/*!
|
||||
* Marks the end of a transfer.
|
||||
*/
|
||||
void EndTransfer() { m_transferFinished = true; }
|
||||
|
||||
private:
|
||||
|
||||
bool m_transferFinished = false;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
49
src/core/vixen/hw/atapi/cmds/proto_nondata.cpp
Normal file
49
src/core/vixen/hw/atapi/cmds/proto_nondata.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
|
||||
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
|
||||
//
|
||||
// [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
|
||||
//
|
||||
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
|
||||
// http://www.bswd.com/sff8020i.pdf
|
||||
//
|
||||
// [s] SCSI Commands Reference Manual 100293068, Rev. J
|
||||
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification. References are prefixed by
|
||||
// the letter in brackets as listed above.
|
||||
#include "proto_nondata.h"
|
||||
|
||||
#include "vixen/log.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace atapi {
|
||||
namespace cmd {
|
||||
|
||||
ATAPINonDataCommand::ATAPINonDataCommand(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver)
|
||||
: IATAPICommand(packetCmdState, driver)
|
||||
{
|
||||
}
|
||||
|
||||
ATAPINonDataCommand::~ATAPINonDataCommand() {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
62
src/core/vixen/hw/atapi/cmds/proto_nondata.h
Normal file
62
src/core/vixen/hw/atapi/cmds/proto_nondata.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
// ATAPI Command set emulation for the Original Xbox
|
||||
// (C) Ivan "StrikerX3" Oliveira
|
||||
//
|
||||
// This code aims to implement the subset of the ATAPI Command set used by the
|
||||
// Original Xbox to access the DVD drive.
|
||||
//
|
||||
// Based on:
|
||||
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
|
||||
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
|
||||
//
|
||||
// [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
|
||||
//
|
||||
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
|
||||
// http://www.bswd.com/sff8020i.pdf
|
||||
//
|
||||
// [s] SCSI Commands Reference Manual 100293068, Rev. J
|
||||
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
|
||||
//
|
||||
// References to particular items in the specification are denoted between brackets
|
||||
// optionally followed by a quote from the specification. References are prefixed by
|
||||
// the letter in brackets as listed above.
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "atapi_command.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace atapi {
|
||||
namespace cmd {
|
||||
|
||||
/*!
|
||||
* Base class for all ATAPI commands that do not transfer data.
|
||||
*/
|
||||
class ATAPINonDataCommand : public IATAPICommand {
|
||||
public:
|
||||
ATAPINonDataCommand(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver);
|
||||
virtual ~ATAPINonDataCommand();
|
||||
|
||||
virtual bool Prepare() override = 0;
|
||||
virtual bool Execute() override = 0;
|
||||
|
||||
PacketOperationType GetOperationType() override { return PktOpNonData; }
|
||||
|
||||
// Technically, a non-data transfer doesn't transfer data.
|
||||
// Technically, if no transfer is needed then the transfer is complete.
|
||||
// So, technically, this should return true.
|
||||
bool IsTransferFinished() override { return true; }
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue