mirror of
https://github.com/akuker/RASCSI.git
synced 2024-06-09 11:29:31 +00:00
Cleanup (memory management, STL containers, type safety) based on SonarCloud report (#845)
* Removed static/global variable * No need for ControllerManager as a singleton * Updated factory handling * Replaced loops * Added const * Added translations, fixed TODO, simplified operation creation * Fixed SonarCloud warnings * Replaced void * by BYTE * * Added explicit mode_page_datetime struct * Unit test updates * Use enum classes * Upddated file size check * Use C++ output formatting * Removed unused code * Use array for garbage buffer * Fixed data returned by READ CAPACITY(10) * For mode pages: Replaced BYTE by std::byte * Use std::byte for INQUIRY * Use std::byte for REQUEST SENSE * Replaced C array by vector * Replaced C style array * Replaced BYTE by std::byte * Replaced DWORD * Use more byte arreys * Updated CTapDriver initialization/deletion * Made status uint32_t instead of DWORD * Replaced command byte array by vector * Updated error handling * Removed obsolete casts * Improved locality of code * rw_command has become obsolete * Dynamically allocate command byte buffer * Simplified receiving commands * Use references * Type safety update, dispatcher update * Removed macros, replaced BOOL/FALSE/TRUE
This commit is contained in:
parent
241e739d3a
commit
119dd55ef0
|
@ -19,7 +19,7 @@
|
|||
//---------------------------------------------------------------------------
|
||||
#define USE_SEL_EVENT_ENABLE // Check SEL signal by event
|
||||
// This avoids an indefinite loop with warnings if there is no RaSCSI hardware
|
||||
// and thus helps with running rasctl and unit test on other hardware.
|
||||
#if !defined(__arm__)
|
||||
// and thus helps with running rasctl and unit test on x86 hardware.
|
||||
#if defined(__x86_64__) || defined(__X86__)
|
||||
#undef USE_SEL_EVENT_ENABLE
|
||||
#endif
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include "phase_handler.h"
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
using namespace std;
|
||||
|
@ -33,20 +34,16 @@ public:
|
|||
RESTART_PI
|
||||
};
|
||||
|
||||
// Internal data definition
|
||||
// TODO Some of these data are probably device specific, and in this case they should be moved.
|
||||
// These data are not internal, otherwise they could all be private
|
||||
using ctrl_t = struct _ctrl_t {
|
||||
// General
|
||||
BUS::phase_t phase = BUS::busfree; // Transition phase
|
||||
BUS::phase_t phase = BUS::phase_t::busfree; // Transition phase
|
||||
|
||||
// commands
|
||||
DWORD cmd[16]; // Command data
|
||||
DWORD status; // Status data
|
||||
vector<int> cmd; // Command data, dynamically allocated per received command
|
||||
uint32_t status; // Status data
|
||||
int message; // Message data
|
||||
|
||||
// Transfer
|
||||
// TODO Try to get rid of the static buffer
|
||||
BYTE *buffer; // Transfer data buffer
|
||||
int bufsize; // Transfer data buffer size
|
||||
uint32_t blocks; // Number of transfer blocks
|
||||
|
@ -58,7 +55,7 @@ public:
|
|||
unordered_map<int, PrimaryDevice *> luns;
|
||||
};
|
||||
|
||||
AbstractController(shared_ptr<BUS> bus, int target_id) : bus(bus), target_id(target_id) {}
|
||||
AbstractController(shared_ptr<BUS> bus, int target_id) : target_id(target_id), bus(bus) {}
|
||||
~AbstractController() override = default;
|
||||
AbstractController(AbstractController&) = delete;
|
||||
AbstractController& operator=(const AbstractController&) = delete;
|
||||
|
@ -89,14 +86,13 @@ public:
|
|||
// TODO Do not expose internal data
|
||||
ctrl_t* GetCtrl() { return &ctrl; }
|
||||
|
||||
int target_id;
|
||||
|
||||
protected:
|
||||
|
||||
scsi_defs::scsi_command GetOpcode() const { return (scsi_defs::scsi_command)ctrl.cmd[0]; }
|
||||
|
||||
shared_ptr<BUS> bus;
|
||||
|
||||
ctrl_t ctrl = {};
|
||||
|
||||
private:
|
||||
|
||||
int target_id;
|
||||
};
|
||||
|
|
|
@ -15,13 +15,7 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
ControllerManager& ControllerManager::instance()
|
||||
{
|
||||
static ControllerManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool ControllerManager::CreateScsiController(shared_ptr<BUS> bus, PrimaryDevice *device) const
|
||||
bool ControllerManager::CreateScsiController(shared_ptr<BUS> bus, PrimaryDevice *device)
|
||||
{
|
||||
shared_ptr<AbstractController> controller = FindController(device->GetId());
|
||||
if (controller == nullptr) {
|
||||
|
@ -49,7 +43,7 @@ shared_ptr<AbstractController> ControllerManager::FindController(int target_id)
|
|||
return it == controllers.end() ? nullptr : it->second;
|
||||
}
|
||||
|
||||
void ControllerManager::DeleteAllControllers() const
|
||||
void ControllerManager::DeleteAllControllers()
|
||||
{
|
||||
controllers.clear();
|
||||
}
|
||||
|
|
|
@ -22,23 +22,23 @@ class PrimaryDevice;
|
|||
|
||||
class ControllerManager
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
ControllerManager() = default;
|
||||
~ControllerManager() = default;
|
||||
ControllerManager(ControllerManager&) = delete;
|
||||
ControllerManager& operator=(const ControllerManager&) = delete;
|
||||
|
||||
public:
|
||||
// Maximum number of controller devices
|
||||
static const int DEVICE_MAX = 8;
|
||||
|
||||
static ControllerManager& instance();
|
||||
|
||||
bool CreateScsiController(shared_ptr<BUS>, PrimaryDevice *) const;
|
||||
bool CreateScsiController(shared_ptr<BUS>, PrimaryDevice *);
|
||||
shared_ptr<AbstractController> IdentifyController(int) const;
|
||||
shared_ptr<AbstractController> FindController(int) const;
|
||||
void DeleteAllControllers() const;
|
||||
void DeleteAllControllers();
|
||||
void ResetAllControllers() const;
|
||||
PrimaryDevice *GetDeviceByIdAndLun(int, int) const;
|
||||
|
||||
inline static unordered_map<int, shared_ptr<AbstractController>> controllers;
|
||||
unordered_map<int, shared_ptr<AbstractController>> controllers;
|
||||
};
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "devices/scsi_host_bridge.h"
|
||||
#include "devices/scsi_daynaport.h"
|
||||
#include "scsi_controller.h"
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace scsi_defs;
|
||||
|
||||
|
@ -39,7 +41,7 @@ ScsiController::~ScsiController()
|
|||
|
||||
void ScsiController::Reset()
|
||||
{
|
||||
SetPhase(BUS::busfree);
|
||||
SetPhase(BUS::phase_t::busfree);
|
||||
ctrl.status = 0x00;
|
||||
ctrl.message = 0x00;
|
||||
execstart = 0;
|
||||
|
@ -92,35 +94,35 @@ BUS::phase_t ScsiController::Process(int id)
|
|||
try {
|
||||
// Phase processing
|
||||
switch (ctrl.phase) {
|
||||
case BUS::busfree:
|
||||
case BUS::phase_t::busfree:
|
||||
BusFree();
|
||||
break;
|
||||
|
||||
case BUS::selection:
|
||||
case BUS::phase_t::selection:
|
||||
Selection();
|
||||
break;
|
||||
|
||||
case BUS::dataout:
|
||||
case BUS::phase_t::dataout:
|
||||
DataOut();
|
||||
break;
|
||||
|
||||
case BUS::datain:
|
||||
case BUS::phase_t::datain:
|
||||
DataIn();
|
||||
break;
|
||||
|
||||
case BUS::command:
|
||||
case BUS::phase_t::command:
|
||||
Command();
|
||||
break;
|
||||
|
||||
case BUS::status:
|
||||
case BUS::phase_t::status:
|
||||
Status();
|
||||
break;
|
||||
|
||||
case BUS::msgout:
|
||||
case BUS::phase_t::msgout:
|
||||
MsgOut();
|
||||
break;
|
||||
|
||||
case BUS::msgin:
|
||||
case BUS::phase_t::msgin:
|
||||
MsgIn();
|
||||
break;
|
||||
|
||||
|
@ -146,10 +148,10 @@ BUS::phase_t ScsiController::Process(int id)
|
|||
|
||||
void ScsiController::BusFree()
|
||||
{
|
||||
if (ctrl.phase != BUS::busfree) {
|
||||
if (ctrl.phase != BUS::phase_t::busfree) {
|
||||
LOGTRACE("%s Bus free phase", __PRETTY_FUNCTION__)
|
||||
|
||||
SetPhase(BUS::busfree);
|
||||
SetPhase(BUS::phase_t::busfree);
|
||||
|
||||
bus->SetREQ(false);
|
||||
bus->SetMSG(false);
|
||||
|
@ -206,7 +208,7 @@ void ScsiController::BusFree()
|
|||
|
||||
void ScsiController::Selection()
|
||||
{
|
||||
if (ctrl.phase != BUS::selection) {
|
||||
if (ctrl.phase != BUS::phase_t::selection) {
|
||||
// A different device controller was selected
|
||||
if (int id = 1 << GetTargetId(); (bus->GetDAT() & id) == 0) {
|
||||
return;
|
||||
|
@ -219,7 +221,7 @@ void ScsiController::Selection()
|
|||
|
||||
LOGTRACE("%s Selection Phase Target ID=%d", __PRETTY_FUNCTION__, GetTargetId())
|
||||
|
||||
SetPhase(BUS::selection);
|
||||
SetPhase(BUS::phase_t::selection);
|
||||
|
||||
// Raise BSY and respond
|
||||
bus->SetBSY(true);
|
||||
|
@ -239,45 +241,37 @@ void ScsiController::Selection()
|
|||
|
||||
void ScsiController::Command()
|
||||
{
|
||||
if (ctrl.phase != BUS::command) {
|
||||
if (ctrl.phase != BUS::phase_t::command) {
|
||||
LOGTRACE("%s Command Phase", __PRETTY_FUNCTION__)
|
||||
|
||||
SetPhase(BUS::command);
|
||||
SetPhase(BUS::phase_t::command);
|
||||
|
||||
bus->SetMSG(false);
|
||||
bus->SetCD(true);
|
||||
bus->SetIO(false);
|
||||
|
||||
// Data transfer is 6 bytes x 1 block
|
||||
ctrl.offset = 0;
|
||||
ctrl.length = 6;
|
||||
ctrl.blocks = 1;
|
||||
|
||||
// If no byte can be received move to the status phase
|
||||
int command_byte_count = bus->CommandHandShake(ctrl.buffer);
|
||||
if (!command_byte_count) {
|
||||
LOGERROR("%s No command bytes received", __PRETTY_FUNCTION__)
|
||||
Error(sense_key::ABORTED_COMMAND);
|
||||
return;
|
||||
}
|
||||
|
||||
ctrl.length = GPIOBUS::GetCommandByteCount(ctrl.buffer[0]);
|
||||
int actual_count = bus->CommandHandShake(ctrl.buffer);
|
||||
int command_byte_count = GPIOBUS::GetCommandByteCount(ctrl.buffer[0]);
|
||||
|
||||
// If not able to receive all, move to the status phase
|
||||
if (command_byte_count != (int)ctrl.length) {
|
||||
if (actual_count != command_byte_count) {
|
||||
LOGERROR("%s Command byte count mismatch: expected %d bytes, received %d byte(s)", __PRETTY_FUNCTION__,
|
||||
command_byte_count, actual_count)
|
||||
Error(sense_key::ABORTED_COMMAND);
|
||||
return;
|
||||
}
|
||||
|
||||
// Command data transfer
|
||||
for (int i = 0; i < (int)ctrl.length; i++) {
|
||||
ctrl.cmd[i] = ctrl.buffer[i];
|
||||
LOGTRACE("%s CDB[%d]=$%02X",__PRETTY_FUNCTION__, i, ctrl.cmd[i])
|
||||
}
|
||||
ctrl.cmd.resize(command_byte_count);
|
||||
|
||||
// Command data transfer
|
||||
stringstream s;
|
||||
for (int i = 0; i < command_byte_count; i++) {
|
||||
ctrl.cmd[i] = ctrl.buffer[i];
|
||||
s << setfill('0') << setw(2) << hex << ctrl.cmd[i];
|
||||
}
|
||||
LOGTRACE("%s CDB=$%s",__PRETTY_FUNCTION__, s.str().c_str())
|
||||
|
||||
// Clear length and block
|
||||
ctrl.length = 0;
|
||||
ctrl.blocks = 0;
|
||||
|
||||
Execute();
|
||||
}
|
||||
|
@ -285,9 +279,9 @@ void ScsiController::Command()
|
|||
|
||||
void ScsiController::Execute()
|
||||
{
|
||||
LOGTRACE("%s Execution phase command $%02X", __PRETTY_FUNCTION__, (unsigned int)ctrl.cmd[0])
|
||||
LOGDEBUG("++++ CMD ++++ %s Executing command $%02X", __PRETTY_FUNCTION__, (int)GetOpcode())
|
||||
|
||||
SetPhase(BUS::execute);
|
||||
SetPhase(BUS::phase_t::execute);
|
||||
|
||||
// Initialization for data transfer
|
||||
ctrl.offset = 0;
|
||||
|
@ -295,16 +289,13 @@ void ScsiController::Execute()
|
|||
execstart = SysTimer::GetTimerLow();
|
||||
|
||||
// Discard pending sense data from the previous command if the current command is not REQUEST SENSE
|
||||
if ((scsi_command)ctrl.cmd[0] != scsi_command::eCmdRequestSense) {
|
||||
if (GetOpcode() != scsi_command::eCmdRequestSense) {
|
||||
ctrl.status = 0;
|
||||
}
|
||||
|
||||
LOGDEBUG("++++ CMD ++++ %s Executing command $%02X", __PRETTY_FUNCTION__, (unsigned int)ctrl.cmd[0])
|
||||
|
||||
int lun = GetEffectiveLun();
|
||||
if (!HasDeviceForLun(lun)) {
|
||||
if ((scsi_command)ctrl.cmd[0] != scsi_command::eCmdInquiry &&
|
||||
(scsi_command)ctrl.cmd[0] != scsi_command::eCmdRequestSense) {
|
||||
if (GetOpcode() != scsi_command::eCmdInquiry && GetOpcode() != scsi_command::eCmdRequestSense) {
|
||||
LOGDEBUG("Invalid LUN %d for ID %d", lun, GetTargetId())
|
||||
|
||||
Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_LUN);
|
||||
|
@ -322,13 +313,13 @@ void ScsiController::Execute()
|
|||
PrimaryDevice *device = GetDeviceForLun(lun);
|
||||
|
||||
// Discard pending sense data from the previous command if the current command is not REQUEST SENSE
|
||||
if ((scsi_command)ctrl.cmd[0] != scsi_command::eCmdRequestSense) {
|
||||
if (GetOpcode() != scsi_command::eCmdRequestSense) {
|
||||
device->SetStatusCode(0);
|
||||
}
|
||||
|
||||
try {
|
||||
if (!device->Dispatch()) {
|
||||
LOGTRACE("ID %d LUN %d received unsupported command: $%02X", GetTargetId(), lun, (BYTE)ctrl.cmd[0])
|
||||
if (!device->Dispatch(GetOpcode())) {
|
||||
LOGTRACE("ID %d LUN %d received unsupported command: $%02X", GetTargetId(), lun, (int)GetOpcode())
|
||||
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
|
||||
}
|
||||
|
@ -340,7 +331,7 @@ void ScsiController::Execute()
|
|||
}
|
||||
|
||||
// SCSI-2 p.104 4.4.3 Incorrect logical unit handling
|
||||
if ((scsi_command)ctrl.cmd[0] == scsi_command::eCmdInquiry && !HasDeviceForLun(lun)) {
|
||||
if (GetOpcode() == scsi_command::eCmdInquiry && !HasDeviceForLun(lun)) {
|
||||
lun = GetEffectiveLun();
|
||||
|
||||
LOGTRACE("Reporting LUN %d for device ID %d as not supported", lun, device->GetId())
|
||||
|
@ -351,7 +342,7 @@ void ScsiController::Execute()
|
|||
|
||||
void ScsiController::Status()
|
||||
{
|
||||
if (ctrl.phase != BUS::status) {
|
||||
if (ctrl.phase != BUS::phase_t::status) {
|
||||
// Minimum execution time
|
||||
if (execstart > 0) {
|
||||
Sleep();
|
||||
|
@ -359,9 +350,9 @@ void ScsiController::Status()
|
|||
SysTimer::SleepUsec(5);
|
||||
}
|
||||
|
||||
LOGTRACE("%s Status Phase $%02X",__PRETTY_FUNCTION__, (unsigned int)ctrl.status)
|
||||
LOGTRACE("%s Status Phase $%02X",__PRETTY_FUNCTION__, ctrl.status)
|
||||
|
||||
SetPhase(BUS::status);
|
||||
SetPhase(BUS::phase_t::status);
|
||||
|
||||
// Signal line operated by the target
|
||||
bus->SetMSG(false);
|
||||
|
@ -382,10 +373,10 @@ void ScsiController::Status()
|
|||
|
||||
void ScsiController::MsgIn()
|
||||
{
|
||||
if (ctrl.phase != BUS::msgin) {
|
||||
if (ctrl.phase != BUS::phase_t::msgin) {
|
||||
LOGTRACE("%s Message In phase", __PRETTY_FUNCTION__)
|
||||
|
||||
SetPhase(BUS::msgin);
|
||||
SetPhase(BUS::phase_t::msgin);
|
||||
|
||||
bus->SetMSG(true);
|
||||
bus->SetCD(true);
|
||||
|
@ -406,17 +397,17 @@ void ScsiController::MsgOut()
|
|||
{
|
||||
LOGTRACE("%s ID %d",__PRETTY_FUNCTION__, GetTargetId())
|
||||
|
||||
if (ctrl.phase != BUS::msgout) {
|
||||
if (ctrl.phase != BUS::phase_t::msgout) {
|
||||
LOGTRACE("Message Out Phase")
|
||||
|
||||
// process the IDENTIFY message
|
||||
if (ctrl.phase == BUS::selection) {
|
||||
if (ctrl.phase == BUS::phase_t::selection) {
|
||||
scsi.atnmsg = true;
|
||||
scsi.msc = 0;
|
||||
memset(scsi.msb, 0x00, sizeof(scsi.msb));
|
||||
}
|
||||
|
||||
SetPhase(BUS::msgout);
|
||||
SetPhase(BUS::phase_t::msgout);
|
||||
|
||||
bus->SetMSG(true);
|
||||
bus->SetCD(true);
|
||||
|
@ -435,7 +426,7 @@ void ScsiController::MsgOut()
|
|||
|
||||
void ScsiController::DataIn()
|
||||
{
|
||||
if (ctrl.phase != BUS::datain) {
|
||||
if (ctrl.phase != BUS::phase_t::datain) {
|
||||
// Minimum execution time
|
||||
if (execstart > 0) {
|
||||
Sleep();
|
||||
|
@ -449,7 +440,7 @@ void ScsiController::DataIn()
|
|||
|
||||
LOGTRACE("%s Going into Data-in Phase", __PRETTY_FUNCTION__)
|
||||
|
||||
SetPhase(BUS::datain);
|
||||
SetPhase(BUS::phase_t::datain);
|
||||
|
||||
bus->SetMSG(false);
|
||||
bus->SetCD(false);
|
||||
|
@ -467,7 +458,7 @@ void ScsiController::DataIn()
|
|||
|
||||
void ScsiController::DataOut()
|
||||
{
|
||||
if (ctrl.phase != BUS::dataout) {
|
||||
if (ctrl.phase != BUS::phase_t::dataout) {
|
||||
// Minimum execution time
|
||||
if (execstart > 0) {
|
||||
Sleep();
|
||||
|
@ -481,7 +472,7 @@ void ScsiController::DataOut()
|
|||
|
||||
LOGTRACE("%s Data out phase", __PRETTY_FUNCTION__)
|
||||
|
||||
SetPhase(BUS::dataout);
|
||||
SetPhase(BUS::phase_t::dataout);
|
||||
|
||||
// Signal line operated by the target
|
||||
bus->SetMSG(false);
|
||||
|
@ -509,24 +500,24 @@ void ScsiController::Error(sense_key sense_key, asc asc, status status)
|
|||
}
|
||||
|
||||
// Bus free for status phase and message in phase
|
||||
if (ctrl.phase == BUS::status || ctrl.phase == BUS::msgin) {
|
||||
if (ctrl.phase == BUS::phase_t::status || ctrl.phase == BUS::phase_t::msgin) {
|
||||
BusFree();
|
||||
return;
|
||||
}
|
||||
|
||||
int lun = GetEffectiveLun();
|
||||
if (!HasDeviceForLun(lun) || asc == INVALID_LUN) {
|
||||
if (!HasDeviceForLun(lun) || asc == asc::INVALID_LUN) {
|
||||
assert(HasDeviceForLun(0));
|
||||
|
||||
lun = 0;
|
||||
}
|
||||
|
||||
if (sense_key || asc) {
|
||||
if (sense_key != sense_key::NO_SENSE || asc != asc::NO_ADDITIONAL_SENSE_INFORMATION) {
|
||||
// Set Sense Key and ASC for a subsequent REQUEST SENSE
|
||||
GetDeviceForLun(lun)->SetStatusCode((sense_key << 16) | (asc << 8));
|
||||
GetDeviceForLun(lun)->SetStatusCode(((int)sense_key << 16) | ((int)asc << 8));
|
||||
}
|
||||
|
||||
ctrl.status = status;
|
||||
ctrl.status = (uint32_t)status;
|
||||
ctrl.message = 0x00;
|
||||
|
||||
LOGTRACE("%s Error (to status phase)", __PRETTY_FUNCTION__)
|
||||
|
@ -564,7 +555,7 @@ void ScsiController::Send()
|
|||
bool result = true;
|
||||
|
||||
// Processing after data collection (read/data-in only)
|
||||
if (ctrl.phase == BUS::datain && ctrl.blocks != 0) {
|
||||
if (ctrl.phase == BUS::phase_t::datain && ctrl.blocks != 0) {
|
||||
// set next buffer (set offset, length)
|
||||
result = XferIn(ctrl.buffer);
|
||||
LOGTRACE("%s%s", __PRETTY_FUNCTION__, (" Processing after data collection. Blocks: " + to_string(ctrl.blocks)).c_str())
|
||||
|
@ -585,10 +576,10 @@ void ScsiController::Send()
|
|||
}
|
||||
|
||||
// Move to next phase
|
||||
LOGTRACE("%s Move to next phase %s (%d)", __PRETTY_FUNCTION__, BUS::GetPhaseStrRaw(ctrl.phase), ctrl.phase)
|
||||
LOGTRACE("%s Move to next phase %s (%d)", __PRETTY_FUNCTION__, BUS::GetPhaseStrRaw(ctrl.phase), (int)ctrl.phase)
|
||||
switch (ctrl.phase) {
|
||||
// Message in phase
|
||||
case BUS::msgin:
|
||||
case BUS::phase_t::msgin:
|
||||
// Completed sending response to extended message of IDENTIFY message
|
||||
if (scsi.atnmsg) {
|
||||
// flag off
|
||||
|
@ -603,13 +594,13 @@ void ScsiController::Send()
|
|||
break;
|
||||
|
||||
// Data-in Phase
|
||||
case BUS::datain:
|
||||
case BUS::phase_t::datain:
|
||||
// status phase
|
||||
Status();
|
||||
break;
|
||||
|
||||
// status phase
|
||||
case BUS::status:
|
||||
case BUS::phase_t::status:
|
||||
// Message in phase
|
||||
ctrl.length = 1;
|
||||
ctrl.blocks = 1;
|
||||
|
@ -641,13 +632,13 @@ void ScsiController::Receive()
|
|||
|
||||
// Length != 0 if received
|
||||
if (ctrl.length != 0) {
|
||||
LOGTRACE("%s Length is %d bytes", __PRETTY_FUNCTION__, (int)ctrl.length)
|
||||
LOGTRACE("%s Length is %d bytes", __PRETTY_FUNCTION__, ctrl.length)
|
||||
// Receive
|
||||
len = bus->ReceiveHandShake(&ctrl.buffer[ctrl.offset], ctrl.length);
|
||||
|
||||
// If not able to receive all, move to status phase
|
||||
if (len != (int)ctrl.length) {
|
||||
LOGERROR("%s Not able to receive %d bytes of data, only received %d",__PRETTY_FUNCTION__, (int)ctrl.length, len)
|
||||
LOGERROR("%s Not able to receive %d bytes of data, only received %d",__PRETTY_FUNCTION__, ctrl.length, len)
|
||||
Error(sense_key::ABORTED_COMMAND);
|
||||
return;
|
||||
}
|
||||
|
@ -665,7 +656,7 @@ void ScsiController::Receive()
|
|||
// Processing after receiving data (by phase)
|
||||
LOGTRACE("%s ctrl.phase: %d (%s)",__PRETTY_FUNCTION__, (int)ctrl.phase, BUS::GetPhaseStrRaw(ctrl.phase))
|
||||
switch (ctrl.phase) {
|
||||
case BUS::dataout:
|
||||
case BUS::phase_t::dataout:
|
||||
if (ctrl.blocks == 0) {
|
||||
// End with this buffer
|
||||
result = XferOut(false);
|
||||
|
@ -675,7 +666,7 @@ void ScsiController::Receive()
|
|||
}
|
||||
break;
|
||||
|
||||
case BUS::msgout:
|
||||
case BUS::phase_t::msgout:
|
||||
ctrl.message = ctrl.buffer[0];
|
||||
if (!XferMsg(ctrl.message)) {
|
||||
// Immediately free the bus if message output fails
|
||||
|
@ -706,7 +697,7 @@ void ScsiController::Receive()
|
|||
|
||||
// Move to next phase
|
||||
switch (ctrl.phase) {
|
||||
case BUS::command:
|
||||
case BUS::phase_t::command:
|
||||
len = GPIOBUS::GetCommandByteCount(ctrl.buffer[0]);
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
|
@ -717,7 +708,7 @@ void ScsiController::Receive()
|
|||
Execute();
|
||||
break;
|
||||
|
||||
case BUS::msgout:
|
||||
case BUS::phase_t::msgout:
|
||||
// Continue message out phase as long as ATN keeps asserting
|
||||
if (bus->GetATN()) {
|
||||
// Data transfer is 1 byte x 1 block
|
||||
|
@ -801,7 +792,7 @@ void ScsiController::Receive()
|
|||
Command();
|
||||
break;
|
||||
|
||||
case BUS::dataout:
|
||||
case BUS::phase_t::dataout:
|
||||
FlushUnit();
|
||||
|
||||
Status();
|
||||
|
@ -815,7 +806,7 @@ void ScsiController::Receive()
|
|||
|
||||
bool ScsiController::XferMsg(int msg)
|
||||
{
|
||||
assert(ctrl.phase == BUS::msgout);
|
||||
assert(ctrl.phase == BUS::phase_t::msgout);
|
||||
|
||||
// Save message out data
|
||||
if (scsi.atnmsg) {
|
||||
|
@ -866,11 +857,11 @@ void ScsiController::ReceiveBytes()
|
|||
LOGTRACE("%s ctrl.phase: %d (%s)",__PRETTY_FUNCTION__, (int)ctrl.phase, BUS::GetPhaseStrRaw(ctrl.phase))
|
||||
switch (ctrl.phase) {
|
||||
|
||||
case BUS::dataout:
|
||||
case BUS::phase_t::dataout:
|
||||
result = XferOut(false);
|
||||
break;
|
||||
|
||||
case BUS::msgout:
|
||||
case BUS::phase_t::msgout:
|
||||
ctrl.message = ctrl.buffer[0];
|
||||
if (!XferMsg(ctrl.message)) {
|
||||
// Immediately free the bus if message output fails
|
||||
|
@ -894,7 +885,7 @@ void ScsiController::ReceiveBytes()
|
|||
|
||||
// Move to next phase
|
||||
switch (ctrl.phase) {
|
||||
case BUS::command:
|
||||
case BUS::phase_t::command:
|
||||
len = GPIOBUS::GetCommandByteCount(ctrl.buffer[0]);
|
||||
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
|
@ -905,7 +896,7 @@ void ScsiController::ReceiveBytes()
|
|||
Execute();
|
||||
break;
|
||||
|
||||
case BUS::msgout:
|
||||
case BUS::phase_t::msgout:
|
||||
// Continue message out phase as long as ATN keeps asserting
|
||||
if (bus->GetATN()) {
|
||||
// Data transfer is 1 byte x 1 block
|
||||
|
@ -989,7 +980,7 @@ void ScsiController::ReceiveBytes()
|
|||
Command();
|
||||
break;
|
||||
|
||||
case BUS::dataout:
|
||||
case BUS::phase_t::dataout:
|
||||
Status();
|
||||
break;
|
||||
|
||||
|
@ -1001,7 +992,7 @@ void ScsiController::ReceiveBytes()
|
|||
|
||||
bool ScsiController::XferOut(bool cont)
|
||||
{
|
||||
assert(ctrl.phase == BUS::dataout);
|
||||
assert(ctrl.phase == BUS::phase_t::dataout);
|
||||
|
||||
if (!is_byte_transfer) {
|
||||
return XferOutBlockOriented(cont);
|
||||
|
@ -1010,18 +1001,18 @@ bool ScsiController::XferOut(bool cont)
|
|||
is_byte_transfer = false;
|
||||
|
||||
if (auto device = GetDeviceForLun(GetEffectiveLun());
|
||||
device != nullptr && ctrl.cmd[0] == scsi_command::eCmdWrite6) {
|
||||
device != nullptr && GetOpcode() == scsi_command::eCmdWrite6) {
|
||||
return device->WriteByteSequence(ctrl.buffer, bytes_to_transfer);
|
||||
}
|
||||
|
||||
LOGWARN("Received an unexpected command ($%02X) in %s", (WORD)ctrl.cmd[0] , __PRETTY_FUNCTION__)
|
||||
LOGWARN("Received an unexpected command ($%02X) in %s", (int)GetOpcode(), __PRETTY_FUNCTION__)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ScsiController::FlushUnit()
|
||||
{
|
||||
assert(ctrl.phase == BUS::dataout);
|
||||
assert(ctrl.phase == BUS::phase_t::dataout);
|
||||
|
||||
auto disk = dynamic_cast<Disk *>(GetDeviceForLun(GetEffectiveLun()));
|
||||
if (disk == nullptr) {
|
||||
|
@ -1029,18 +1020,18 @@ void ScsiController::FlushUnit()
|
|||
}
|
||||
|
||||
// WRITE system only
|
||||
switch ((ScsiController::rw_command)ctrl.cmd[0]) {
|
||||
case ScsiController::eRwCmdWrite6:
|
||||
case ScsiController::eRwCmdWrite10:
|
||||
case ScsiController::eRwCmdWrite16:
|
||||
case ScsiController::eRwCmdWriteLong10:
|
||||
case ScsiController::eRwCmdWriteLong16:
|
||||
case ScsiController::eRwCmdVerify10:
|
||||
case ScsiController::eRwCmdVerify16:
|
||||
switch (GetOpcode()) {
|
||||
case scsi_command::eCmdWrite6:
|
||||
case scsi_command::eCmdWrite10:
|
||||
case scsi_command::eCmdWrite16:
|
||||
case scsi_command::eCmdWriteLong10:
|
||||
case scsi_command::eCmdWriteLong16:
|
||||
case scsi_command::eCmdVerify10:
|
||||
case scsi_command::eCmdVerify16:
|
||||
break;
|
||||
|
||||
case ScsiController::eRwCmdModeSelect6:
|
||||
case ScsiController::eRwCmdModeSelect10:
|
||||
case scsi_command::eCmdModeSelect6:
|
||||
case scsi_command::eCmdModeSelect10:
|
||||
// TODO What is this special handling of ModeSelect good for?
|
||||
// Without it we would not need this method at all.
|
||||
// ModeSelect is already handled in XferOutBlockOriented(). Why would it have to be handled once more?
|
||||
|
@ -1048,18 +1039,18 @@ void ScsiController::FlushUnit()
|
|||
disk->ModeSelect(ctrl.cmd, ctrl.buffer, ctrl.offset);
|
||||
}
|
||||
catch(const scsi_error_exception& e) {
|
||||
LOGWARN("Error occured while processing Mode Select command %02X\n", (unsigned char)ctrl.cmd[0])
|
||||
LOGWARN("Error occured while processing Mode Select command %02X\n", (int)GetOpcode())
|
||||
Error(e.get_sense_key(), e.get_asc(), e.get_status());
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case ScsiController::eRwCmdSetMcastAddr:
|
||||
case scsi_command::eCmdSetMcastAddr:
|
||||
// TODO: Eventually, we should store off the multicast address configuration data here...
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGWARN("Received an unexpected flush command $%02X\n",(WORD)ctrl.cmd[0])
|
||||
LOGWARN("Received an unexpected flush command $%02X\n", (int)GetOpcode())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1074,9 +1065,9 @@ void ScsiController::FlushUnit()
|
|||
//---------------------------------------------------------------------------
|
||||
bool ScsiController::XferIn(BYTE *buf)
|
||||
{
|
||||
assert(ctrl.phase == BUS::datain);
|
||||
assert(ctrl.phase == BUS::phase_t::datain);
|
||||
|
||||
LOGTRACE("%s ctrl.cmd[0]=%02X", __PRETTY_FUNCTION__, (unsigned int)ctrl.cmd[0])
|
||||
LOGTRACE("%s command=%02X", __PRETTY_FUNCTION__, (int)GetOpcode())
|
||||
|
||||
int lun = GetEffectiveLun();
|
||||
if (!HasDeviceForLun(lun)) {
|
||||
|
@ -1084,13 +1075,13 @@ bool ScsiController::XferIn(BYTE *buf)
|
|||
}
|
||||
|
||||
// Limited to read commands
|
||||
switch (ctrl.cmd[0]) {
|
||||
case eRwCmdRead6:
|
||||
case eRwCmdRead10:
|
||||
case eRwCmdRead16:
|
||||
switch (GetOpcode()) {
|
||||
case scsi_command::eCmdRead6:
|
||||
case scsi_command::eCmdRead10:
|
||||
case scsi_command::eCmdRead16:
|
||||
// Read from disk
|
||||
try {
|
||||
ctrl.length = ((Disk *)GetDeviceForLun(lun))->Read(ctrl.cmd, buf, ctrl.next);
|
||||
ctrl.length = (static_cast<Disk *>(GetDeviceForLun(lun)))->Read(ctrl.cmd, buf, ctrl.next);
|
||||
}
|
||||
catch(const scsi_error_exception&) {
|
||||
// If there is an error, go to the status phase
|
||||
|
@ -1109,7 +1100,6 @@ bool ScsiController::XferIn(BYTE *buf)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Succeeded in setting the buffer
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1129,9 +1119,9 @@ bool ScsiController::XferOutBlockOriented(bool cont)
|
|||
}
|
||||
|
||||
// Limited to write commands
|
||||
switch (ctrl.cmd[0]) {
|
||||
case eRwCmdModeSelect6:
|
||||
case eRwCmdModeSelect10:
|
||||
switch (GetOpcode()) {
|
||||
case scsi_command::eCmdModeSelect6:
|
||||
case scsi_command::eCmdModeSelect10:
|
||||
try {
|
||||
disk->ModeSelect(ctrl.cmd, ctrl.buffer, ctrl.offset);
|
||||
}
|
||||
|
@ -1141,12 +1131,12 @@ bool ScsiController::XferOutBlockOriented(bool cont)
|
|||
}
|
||||
break;
|
||||
|
||||
case eRwCmdWrite6:
|
||||
case eRwCmdWrite10:
|
||||
case eRwCmdWrite16:
|
||||
case scsi_command::eCmdWrite6:
|
||||
case scsi_command::eCmdWrite10:
|
||||
case scsi_command::eCmdWrite16:
|
||||
// TODO Verify has to verify, not to write
|
||||
case eRwCmdVerify10:
|
||||
case eRwCmdVerify16:
|
||||
case scsi_command::eCmdVerify10:
|
||||
case scsi_command::eCmdVerify16:
|
||||
{
|
||||
// Special case Write function for brige
|
||||
// TODO This class must not know about SCSIBR
|
||||
|
@ -1199,12 +1189,12 @@ bool ScsiController::XferOutBlockOriented(bool cont)
|
|||
break;
|
||||
}
|
||||
|
||||
case eRwCmdSetMcastAddr:
|
||||
case scsi_command::eCmdSetMcastAddr:
|
||||
LOGTRACE("%s Done with DaynaPort Set Multicast Address", __PRETTY_FUNCTION__)
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGWARN("Received an unexpected command ($%02X) in %s", (WORD)ctrl.cmd[0] , __PRETTY_FUNCTION__)
|
||||
LOGWARN("Received an unexpected command ($%02X) in %s", (int)GetOpcode(), __PRETTY_FUNCTION__)
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,23 +37,6 @@ class ScsiController : public AbstractController
|
|||
|
||||
const int DEFAULT_BUFFER_SIZE = 0x1000;
|
||||
|
||||
enum rw_command : int {
|
||||
eRwCmdRead6 = 0x08,
|
||||
eRwCmdWrite6 = 0x0A,
|
||||
eRwCmdSetMcastAddr = 0x0D, // DaynaPort specific command
|
||||
eRwCmdModeSelect6 = 0x15,
|
||||
eRwCmdRead10 = 0x28,
|
||||
eRwCmdWrite10 = 0x2A,
|
||||
eRwCmdVerify10 = 0x2E,
|
||||
eRwCmdVerify = 0x2F,
|
||||
eRwCmdModeSelect10 = 0x55,
|
||||
eRwCmdRead16 = 0x88,
|
||||
eRwCmdWrite16 = 0x8A,
|
||||
eRwCmdVerify16 = 0x8F,
|
||||
eRwCmdWriteLong10 = 0x3F,
|
||||
eRwCmdWriteLong16 = 0x9F
|
||||
};
|
||||
|
||||
using scsi_t = struct _scsi_t {
|
||||
// Synchronous transfer
|
||||
bool syncenable; // Synchronous transfer possible
|
||||
|
@ -95,7 +78,7 @@ public:
|
|||
private:
|
||||
|
||||
// Execution start time
|
||||
DWORD execstart = 0;
|
||||
uint32_t execstart = 0;
|
||||
|
||||
// The initiator ID may be unavailable, e.g. with Atari ACSI and old host adapters
|
||||
int initiator_id = UNKNOWN_INITIATOR_ID;
|
||||
|
|
|
@ -108,8 +108,7 @@ void Human68k::namests_t::GetCopyPath(BYTE* szPath) const
|
|||
ASSERT(szPath);
|
||||
|
||||
BYTE* p = szPath;
|
||||
for (size_t i = 0; i < 65; i++) {
|
||||
BYTE c = path[i];
|
||||
for (BYTE c : path) {
|
||||
if (c == '\0')
|
||||
break;
|
||||
if (c == 0x09) {
|
||||
|
@ -226,10 +225,10 @@ void CHostDrv::Init(const TCHAR* szBase, DWORD nFlag)
|
|||
{
|
||||
ASSERT(szBase);
|
||||
ASSERT(strlen(szBase) < FILEPATH_MAX);
|
||||
ASSERT(m_bWriteProtect == FALSE);
|
||||
ASSERT(m_bEnable == FALSE);
|
||||
ASSERT(!m_bWriteProtect);
|
||||
ASSERT(!m_bEnable);
|
||||
ASSERT(m_capCache.sectors == 0);
|
||||
ASSERT(m_bVolumeCache == FALSE);
|
||||
ASSERT(!m_bVolumeCache);
|
||||
ASSERT(m_szVolumeCache[0] == _T('\0'));
|
||||
|
||||
// Confirm that the entity does not exist (just in case)
|
||||
|
@ -241,7 +240,7 @@ void CHostDrv::Init(const TCHAR* szBase, DWORD nFlag)
|
|||
|
||||
// Receive parameters
|
||||
if (nFlag & FSFLAG_WRITE_PROTECT)
|
||||
m_bWriteProtect = TRUE;
|
||||
m_bWriteProtect = true;
|
||||
strcpy(m_szBase, szBase);
|
||||
|
||||
// Remove the last path delimiter in the base path
|
||||
|
@ -268,7 +267,7 @@ void CHostDrv::Init(const TCHAR* szBase, DWORD nFlag)
|
|||
*pClear = _T('\0');
|
||||
|
||||
// Status update
|
||||
m_bEnable = TRUE;
|
||||
m_bEnable = true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -276,10 +275,10 @@ void CHostDrv::Init(const TCHAR* szBase, DWORD nFlag)
|
|||
// Media check
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostDrv::isMediaOffline() const
|
||||
bool CHostDrv::isMediaOffline() const
|
||||
{
|
||||
// Offline status check
|
||||
return m_bEnable == FALSE;
|
||||
return !m_bEnable;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -307,14 +306,14 @@ DWORD CHostDrv::GetStatus() const
|
|||
// Media status settings
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void CHostDrv::SetEnable(BOOL bEnable)
|
||||
void CHostDrv::SetEnable(bool bEnable)
|
||||
{
|
||||
m_bEnable = bEnable;
|
||||
|
||||
if (bEnable == FALSE) {
|
||||
if (!bEnable) {
|
||||
// Clear cache
|
||||
m_capCache.sectors = 0;
|
||||
m_bVolumeCache = FALSE;
|
||||
m_bVolumeCache = false;
|
||||
m_szVolumeCache[0] = _T('\0');
|
||||
}
|
||||
}
|
||||
|
@ -324,11 +323,11 @@ void CHostDrv::SetEnable(BOOL bEnable)
|
|||
// Media change check
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostDrv::CheckMedia()
|
||||
bool CHostDrv::CheckMedia()
|
||||
{
|
||||
// Status update
|
||||
Update();
|
||||
if (m_bEnable == FALSE)
|
||||
if (!m_bEnable)
|
||||
CleanCache();
|
||||
|
||||
return m_bEnable;
|
||||
|
@ -342,10 +341,8 @@ BOOL CHostDrv::CheckMedia()
|
|||
void CHostDrv::Update()
|
||||
{
|
||||
// Considered as media insertion
|
||||
BOOL bEnable = TRUE;
|
||||
|
||||
// Media status reflected
|
||||
SetEnable(bEnable);
|
||||
SetEnable(true);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -357,7 +354,7 @@ void CHostDrv::Eject()
|
|||
{
|
||||
// Media discharge
|
||||
CleanCache();
|
||||
SetEnable(FALSE);
|
||||
SetEnable(false);
|
||||
|
||||
// Status update
|
||||
Update();
|
||||
|
@ -382,7 +379,7 @@ void CHostDrv::GetVolume(TCHAR* szLabel)
|
|||
}
|
||||
|
||||
// Cache update
|
||||
m_bVolumeCache = TRUE;
|
||||
m_bVolumeCache = true;
|
||||
|
||||
// Transfer content
|
||||
strcpy(szLabel, m_szVolumeCache);
|
||||
|
@ -393,10 +390,10 @@ void CHostDrv::GetVolume(TCHAR* szLabel)
|
|||
/// Get volume label from cache
|
||||
///
|
||||
/// Transfer the cached volume label information.
|
||||
/// If the cache contents are valid return TRUE, if invalid return FALSE.
|
||||
/// Return true if the cache contents are valid.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostDrv::GetVolumeCache(TCHAR* szLabel) const
|
||||
bool CHostDrv::GetVolumeCache(TCHAR* szLabel) const
|
||||
{
|
||||
ASSERT(szLabel);
|
||||
|
||||
|
@ -406,11 +403,6 @@ BOOL CHostDrv::GetVolumeCache(TCHAR* szLabel) const
|
|||
return m_bVolumeCache;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
/// Get Capacity
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
DWORD CHostDrv::GetCapacity(Human68k::capacity_t* pCapacity)
|
||||
{
|
||||
ASSERT(pCapacity);
|
||||
|
@ -447,12 +439,12 @@ DWORD CHostDrv::GetCapacity(Human68k::capacity_t* pCapacity)
|
|||
/// Get capacity from the cache
|
||||
///
|
||||
/// Transfer the capacity data stored in cache.
|
||||
/// If the contents of the cache is valid return TRUE, is invalid return FALSE.
|
||||
/// Return true if the contents of the cache are valid.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostDrv::GetCapacityCache(Human68k::capacity_t* pCapacity) const
|
||||
bool CHostDrv::GetCapacityCache(Human68k::capacity_t* pCapacity) const
|
||||
{
|
||||
ASSERT(pCapacity);
|
||||
assert(pCapacity);
|
||||
|
||||
// Transfer contents
|
||||
memcpy(pCapacity, &m_capCache, sizeof(m_capCache));
|
||||
|
@ -480,7 +472,7 @@ void CHostDrv::CleanCache() const
|
|||
//---------------------------------------------------------------------------
|
||||
void CHostDrv::CleanCache(const BYTE* szHumanPath)
|
||||
{
|
||||
ASSERT(szHumanPath);
|
||||
assert(szHumanPath);
|
||||
|
||||
CHostPath* p = FindCache(szHumanPath);
|
||||
if (p) {
|
||||
|
@ -513,8 +505,6 @@ void CHostDrv::CleanCacheChild(const BYTE* szHumanPath) const
|
|||
//---------------------------------------------------------------------------
|
||||
void CHostDrv::DeleteCache(const BYTE* szHumanPath)
|
||||
{
|
||||
ASSERT(szHumanPath);
|
||||
|
||||
auto p = FindCache(szHumanPath);
|
||||
if (p) {
|
||||
delete p;
|
||||
|
@ -712,7 +702,7 @@ CHostPath* CHostDrv::MakeCache(CHostFiles* pFiles)
|
|||
/// Set all Human68k parameters once more.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostDrv::Find(CHostFiles* pFiles)
|
||||
bool CHostDrv::Find(CHostFiles* pFiles)
|
||||
{
|
||||
ASSERT(pFiles);
|
||||
|
||||
|
@ -722,7 +712,7 @@ BOOL CHostDrv::Find(CHostFiles* pFiles)
|
|||
pPath = MakeCache(pFiles);
|
||||
if (pPath == nullptr) {
|
||||
CleanCache();
|
||||
return FALSE; // Error: Failed to build cache
|
||||
return false; // Error: Failed to build cache
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -731,13 +721,13 @@ BOOL CHostDrv::Find(CHostFiles* pFiles)
|
|||
|
||||
// Exit if only path name
|
||||
if (pFiles->isPathOnly()) {
|
||||
return TRUE; // Normal exit: only path name
|
||||
return true; // Normal exit: only path name
|
||||
}
|
||||
|
||||
// Find file name
|
||||
const CHostFilename* pFilename = pFiles->Find(pPath);
|
||||
if (pFilename == nullptr) {
|
||||
return FALSE; // Error: Could not get file name
|
||||
return false; // Error: Could not get file name
|
||||
}
|
||||
|
||||
// Store the Human68k side search results
|
||||
|
@ -746,7 +736,7 @@ BOOL CHostDrv::Find(CHostFiles* pFiles)
|
|||
// Store the host side full path name
|
||||
pFiles->AddResult(pFilename->GetHost());
|
||||
|
||||
return TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -809,7 +799,7 @@ void CHostFilename::ConvertHuman(int nCount)
|
|||
(m_szHost[1] == _T('\0') || (m_szHost[1] == _T('.') && m_szHost[2] == _T('\0')))) {
|
||||
strcpy((char*)m_szHuman, m_szHost);
|
||||
|
||||
m_bCorrect = TRUE;
|
||||
m_bCorrect = true;
|
||||
m_pszHumanLast = m_szHuman + strlen((const char*)m_szHuman);
|
||||
m_pszHumanExt = m_pszHumanLast;
|
||||
return;
|
||||
|
@ -1002,22 +992,22 @@ void CHostFilename::ConvertHuman(int nCount)
|
|||
*pWrite = '\0';
|
||||
|
||||
// Confirm the conversion results
|
||||
m_bCorrect = TRUE;
|
||||
m_bCorrect = true;
|
||||
|
||||
// Fail if the base file name does not exist
|
||||
if (m_pszHumanExt <= m_szHuman)
|
||||
m_bCorrect = FALSE;
|
||||
m_bCorrect = false;
|
||||
|
||||
// Fail if the base file name is more than 1 char and ends with a space
|
||||
// While it is theoretically valid to have a base file name exceed 8 chars,
|
||||
// Human68k is unable to handle it, so failing this case too.
|
||||
else if (m_pszHumanExt[-1] == ' ')
|
||||
m_bCorrect = FALSE;
|
||||
m_bCorrect = false;
|
||||
|
||||
// Fail if the conversion result is the same as a special directory name
|
||||
if (m_szHuman[0] == '.' &&
|
||||
(m_szHuman[1] == '\0' || (m_szHuman[1] == '.' && m_szHuman[2] == '\0')))
|
||||
m_bCorrect = FALSE;
|
||||
m_bCorrect = false;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -1033,7 +1023,7 @@ void CHostFilename::CopyHuman(const BYTE* szHuman)
|
|||
ASSERT(strlen((const char*)szHuman) < 23);
|
||||
|
||||
strcpy((char*)m_szHuman, (const char*)szHuman);
|
||||
m_bCorrect = TRUE;
|
||||
m_bCorrect = true;
|
||||
m_pszHumanLast = m_szHuman + strlen((const char*)m_szHuman);
|
||||
m_pszHumanExt = SeparateExt(m_szHuman);
|
||||
}
|
||||
|
@ -1079,7 +1069,7 @@ void CHostFilename::SetEntryName()
|
|||
/// Investigate if the Human68k side name has been processed
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostFilename::isReduce() const
|
||||
bool CHostFilename::isReduce() const
|
||||
{
|
||||
return strcmp((const char *)m_szHost, (const char*)m_szHuman) != 0;
|
||||
}
|
||||
|
@ -1089,7 +1079,7 @@ BOOL CHostFilename::isReduce() const
|
|||
/// Evaluate Human68k directory entry attribute
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostFilename::CheckAttribute(DWORD nHumanAttribute) const
|
||||
int CHostFilename::CheckAttribute(DWORD nHumanAttribute) const
|
||||
{
|
||||
BYTE nAttribute = m_dirHuman.attr;
|
||||
if ((nAttribute & (Human68k::AT_ARCHIVE | Human68k::AT_DIRECTORY | Human68k::AT_VOLUME)) == 0)
|
||||
|
@ -1228,8 +1218,8 @@ int CHostPath::Compare(const BYTE* pFirst, const BYTE* pLast, const BYTE* pBufFi
|
|||
ASSERT(pBufLast);
|
||||
|
||||
// Compare chars
|
||||
BOOL bSkip0 = FALSE;
|
||||
BOOL bSkip1 = FALSE;
|
||||
bool bSkip0 = false;
|
||||
bool bSkip1 = false;
|
||||
for (const BYTE* p = pFirst; p < pLast; p++) {
|
||||
// Read 1 char
|
||||
BYTE c = *p;
|
||||
|
@ -1238,13 +1228,13 @@ int CHostPath::Compare(const BYTE* pFirst, const BYTE* pLast, const BYTE* pBufFi
|
|||
d = *pBufFirst++;
|
||||
|
||||
// Ajust char for comparison
|
||||
if (bSkip0 == FALSE) {
|
||||
if (bSkip1 == FALSE) { // First byte for both c and d
|
||||
if (!bSkip0) {
|
||||
if (!bSkip1) { // First byte for both c and d
|
||||
if ((0x80 <= c && c <= 0x9F) || 0xE0 <= c) { // Specifically 0x81~0x9F 0xE0~0xEF
|
||||
bSkip0 = TRUE;
|
||||
bSkip0 = true;
|
||||
}
|
||||
if ((0x80 <= d && d <= 0x9F) || 0xE0 <= d) { // Specifically 0x81~0x9F 0xE0~0xEF
|
||||
bSkip1 = TRUE;
|
||||
bSkip1 = true;
|
||||
}
|
||||
if (c == d)
|
||||
continue; // Finishes the evaluation here with high probability
|
||||
|
@ -1263,19 +1253,19 @@ int CHostPath::Compare(const BYTE* pFirst, const BYTE* pLast, const BYTE* pBufFi
|
|||
}
|
||||
} else { // Only c is first byte
|
||||
if ((0x80 <= c && c <= 0x9F) || 0xE0 <= c) { // Specifically 0x81~0x9F 0xE0~0xEF
|
||||
bSkip0 = TRUE;
|
||||
bSkip0 = true;
|
||||
}
|
||||
bSkip1 = FALSE;
|
||||
bSkip1 = false;
|
||||
}
|
||||
} else {
|
||||
if (bSkip1 == FALSE) { // Only d is first byte
|
||||
bSkip0 = FALSE;
|
||||
if (!bSkip1) { // Only d is first byte
|
||||
bSkip0 = false;
|
||||
if ((0x80 <= d && d <= 0x9F) || 0xE0 <= d) { // Specifically 0x81~0x9F 0xE0~0xEF
|
||||
bSkip1 = TRUE;
|
||||
bSkip1 = true;
|
||||
}
|
||||
} else { // Second byte for both c and d
|
||||
bSkip0 = FALSE;
|
||||
bSkip1 = FALSE;
|
||||
bSkip0 = false;
|
||||
bSkip1 = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1297,9 +1287,9 @@ int CHostPath::Compare(const BYTE* pFirst, const BYTE* pLast, const BYTE* pBufFi
|
|||
/// Compare Human68k side name
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostPath::isSameHuman(const BYTE* szHuman) const
|
||||
bool CHostPath::isSameHuman(const BYTE* szHuman) const
|
||||
{
|
||||
ASSERT(szHuman);
|
||||
assert(szHuman);
|
||||
|
||||
// Calulate number of chars
|
||||
size_t nLength = strlen((const char*)m_szHuman);
|
||||
|
@ -1307,15 +1297,15 @@ BOOL CHostPath::isSameHuman(const BYTE* szHuman) const
|
|||
|
||||
// Check number of chars
|
||||
if (nLength != n)
|
||||
return FALSE;
|
||||
return false;
|
||||
|
||||
// Compare Human68k path name
|
||||
return Compare(m_szHuman, m_szHuman + nLength, szHuman, szHuman + n) == 0;
|
||||
}
|
||||
|
||||
BOOL CHostPath::isSameChild(const BYTE* szHuman) const
|
||||
bool CHostPath::isSameChild(const BYTE* szHuman) const
|
||||
{
|
||||
ASSERT(szHuman);
|
||||
assert(szHuman);
|
||||
|
||||
// Calulate number of chars
|
||||
size_t nLength = strlen((const char*)m_szHuman);
|
||||
|
@ -1323,7 +1313,7 @@ BOOL CHostPath::isSameChild(const BYTE* szHuman) const
|
|||
|
||||
// Check number of chars
|
||||
if (nLength < n)
|
||||
return FALSE;
|
||||
return false;
|
||||
|
||||
// Compare Human68k path name
|
||||
return Compare(m_szHuman, m_szHuman + n, szHuman, szHuman + n) == 0;
|
||||
|
@ -1459,7 +1449,7 @@ const CHostFilename* CHostPath::FindFilenameWildcard(const BYTE* szHuman, DWORD
|
|||
/// Confirm that the file update has been carried out
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostPath::isRefresh() const
|
||||
bool CHostPath::isRefresh() const
|
||||
{
|
||||
return m_bRefresh;
|
||||
}
|
||||
|
@ -1493,14 +1483,14 @@ void CHostPath::Refresh()
|
|||
strcpy(szPath, m_szHost);
|
||||
|
||||
// Update refresh flag
|
||||
m_bRefresh = FALSE;
|
||||
m_bRefresh = false;
|
||||
|
||||
// Store previous cache contents
|
||||
CRing cRingBackup;
|
||||
m_cRing.InsertRing(&cRingBackup);
|
||||
|
||||
// Register file name
|
||||
BOOL bUpdate = FALSE;
|
||||
bool bUpdate = false;
|
||||
dirent **pd = nullptr;
|
||||
int nument = 0;
|
||||
int maxent = XM6_HOST_DIRENTRY_FILE_MAX;
|
||||
|
@ -1536,7 +1526,7 @@ void CHostPath::Refresh()
|
|||
for (;;) {
|
||||
if (pCache == (ring_t*)&cRingBackup) {
|
||||
pCache = nullptr; // No relevant entry
|
||||
bUpdate = TRUE; // Confirm new entry
|
||||
bUpdate = true; // Confirm new entry
|
||||
pFilename->ConvertHuman();
|
||||
break;
|
||||
}
|
||||
|
@ -1612,7 +1602,7 @@ void CHostPath::Refresh()
|
|||
pRing = pCache; // Use previous cache
|
||||
} else {
|
||||
Free(pCache); // Remove from the next search target
|
||||
bUpdate = TRUE; // Flag for update if no match
|
||||
bUpdate = true; // Flag for update if no match
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1631,14 +1621,13 @@ void CHostPath::Refresh()
|
|||
// Delete remaining cache
|
||||
ring_t* p;
|
||||
while ((p = (ring_t*)cRingBackup.Next()) != (ring_t*)&cRingBackup) {
|
||||
bUpdate = TRUE; // Confirms the decrease in entries due to deletion
|
||||
bUpdate = true; // Confirms the decrease in entries due to deletion
|
||||
Free(p);
|
||||
}
|
||||
|
||||
// Update the identifier if the update has been carried out
|
||||
if (bUpdate)
|
||||
m_nId = ++g_nId;
|
||||
// ASSERT(m_nId);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -1700,8 +1689,7 @@ void CHostPath::Restore() const
|
|||
//---------------------------------------------------------------------------
|
||||
void CHostPath::Release()
|
||||
{
|
||||
|
||||
m_bRefresh = TRUE;
|
||||
m_bRefresh = true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -1714,12 +1702,12 @@ CHostEntry::~CHostEntry()
|
|||
{
|
||||
Clean();
|
||||
|
||||
#ifdef _DEBUG
|
||||
#ifdef DEBUG
|
||||
// Confirm object
|
||||
for (size_t n = 0; n < DRIVE_MAX; n++) {
|
||||
ASSERT(m_pDrv[n] == nullptr);
|
||||
for (const auto& d : m_pDrv) {
|
||||
assert(d == nullptr);
|
||||
}
|
||||
#endif // _DEBUG
|
||||
#endif
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -1729,11 +1717,10 @@ CHostEntry::~CHostEntry()
|
|||
//---------------------------------------------------------------------------
|
||||
void CHostEntry::Init() const
|
||||
{
|
||||
|
||||
#ifdef _DEBUG
|
||||
#ifdef DEBUG
|
||||
// Confirm object
|
||||
for (size_t n = 0; n < DRIVE_MAX; n++) {
|
||||
ASSERT(m_pDrv[n] == nullptr);
|
||||
for (const auto& d : m_pDrv) {
|
||||
assert(d == nullptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -1745,11 +1732,10 @@ void CHostEntry::Init() const
|
|||
//---------------------------------------------------------------------------
|
||||
void CHostEntry::Clean()
|
||||
{
|
||||
|
||||
// Delete object
|
||||
for (size_t n = 0; n < DRIVE_MAX; n++) {
|
||||
delete m_pDrv[n];
|
||||
m_pDrv[n] = nullptr;
|
||||
for (auto& d: m_pDrv) {
|
||||
delete d;
|
||||
d = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1760,10 +1746,9 @@ void CHostEntry::Clean()
|
|||
//---------------------------------------------------------------------------
|
||||
void CHostEntry::CleanCache() const
|
||||
{
|
||||
|
||||
for (size_t i = 0; i < DRIVE_MAX; i++) {
|
||||
if (m_pDrv[i])
|
||||
m_pDrv[i]->CleanCache();
|
||||
for (const auto& d : m_pDrv) {
|
||||
if (d)
|
||||
d->CleanCache();
|
||||
}
|
||||
|
||||
CHostPath::InitId();
|
||||
|
@ -1829,7 +1814,7 @@ void CHostEntry::DeleteCache(DWORD nUnit, const BYTE* szHumanPath) const
|
|||
/// Find host side names (path name + file name (can be abbreviated) + attribute)
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostEntry::Find(DWORD nUnit, CHostFiles* pFiles) const
|
||||
bool CHostEntry::Find(DWORD nUnit, CHostFiles* pFiles) const
|
||||
{
|
||||
ASSERT(pFiles);
|
||||
ASSERT(nUnit < DRIVE_MAX);
|
||||
|
@ -1856,7 +1841,7 @@ void CHostEntry::SetDrv(DWORD nUnit, CHostDrv* pDrv)
|
|||
/// Is it write-protected?
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostEntry::isWriteProtect(DWORD nUnit) const
|
||||
bool CHostEntry::isWriteProtect(DWORD nUnit) const
|
||||
{
|
||||
ASSERT(nUnit < DRIVE_MAX);
|
||||
ASSERT(m_pDrv[nUnit]);
|
||||
|
@ -1869,7 +1854,7 @@ BOOL CHostEntry::isWriteProtect(DWORD nUnit) const
|
|||
/// Is it accessible?
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostEntry::isEnable(DWORD nUnit) const
|
||||
bool CHostEntry::isEnable(DWORD nUnit) const
|
||||
{
|
||||
ASSERT(nUnit < DRIVE_MAX);
|
||||
ASSERT(m_pDrv[nUnit]);
|
||||
|
@ -1882,7 +1867,7 @@ BOOL CHostEntry::isEnable(DWORD nUnit) const
|
|||
/// Media check
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostEntry::isMediaOffline(DWORD nUnit) const
|
||||
bool CHostEntry::isMediaOffline(DWORD nUnit) const
|
||||
{
|
||||
ASSERT(nUnit < DRIVE_MAX);
|
||||
ASSERT(m_pDrv[nUnit]);
|
||||
|
@ -1921,7 +1906,7 @@ DWORD CHostEntry::GetStatus(DWORD nUnit) const
|
|||
/// Media change check
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostEntry::CheckMedia(DWORD nUnit) const
|
||||
bool CHostEntry::CheckMedia(DWORD nUnit) const
|
||||
{
|
||||
ASSERT(nUnit < DRIVE_MAX);
|
||||
ASSERT(m_pDrv[nUnit]);
|
||||
|
@ -1960,7 +1945,7 @@ void CHostEntry::GetVolume(DWORD nUnit, TCHAR* szLabel) const
|
|||
/// Get volume label from cache
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostEntry::GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const
|
||||
bool CHostEntry::GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const
|
||||
{
|
||||
ASSERT(nUnit < DRIVE_MAX);
|
||||
ASSERT(m_pDrv[nUnit]);
|
||||
|
@ -1986,7 +1971,7 @@ DWORD CHostEntry::GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity) cons
|
|||
/// Get cluster size from cache
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostEntry::GetCapacityCache(DWORD nUnit, Human68k::capacity_t* pCapacity) const
|
||||
bool CHostEntry::GetCapacityCache(DWORD nUnit, Human68k::capacity_t* pCapacity) const
|
||||
{
|
||||
ASSERT(nUnit < DRIVE_MAX);
|
||||
ASSERT(m_pDrv[nUnit]);
|
||||
|
@ -2070,7 +2055,7 @@ void CHostFiles::SetPath(const Human68k::namests_t* pNamests)
|
|||
/// Find file on the Human68k side and create data on the host side
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostFiles::Find(DWORD nUnit, const CHostEntry* pEntry)
|
||||
bool CHostFiles::Find(DWORD nUnit, const CHostEntry* pEntry)
|
||||
{
|
||||
ASSERT(pEntry);
|
||||
|
||||
|
@ -2249,7 +2234,7 @@ void CHostFilesManager::Free(CHostFiles* pFiles)
|
|||
/// Set file open mode
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostFcb::SetMode(DWORD nHumanMode)
|
||||
bool CHostFcb::SetMode(DWORD nHumanMode)
|
||||
{
|
||||
switch (nHumanMode & Human68k::OP_MASK) {
|
||||
case Human68k::OP_READ:
|
||||
|
@ -2262,12 +2247,12 @@ BOOL CHostFcb::SetMode(DWORD nHumanMode)
|
|||
m_pszMode = "r+b";
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_bFlag = (nHumanMode & Human68k::OP_SPECIAL) != 0;
|
||||
|
||||
return TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CHostFcb::SetFilename(const TCHAR* szFilename)
|
||||
|
@ -2290,20 +2275,20 @@ void CHostFcb::SetHumanPath(const BYTE* szHumanPath)
|
|||
//
|
||||
/// Create file
|
||||
///
|
||||
/// Return FALSE if error is thrown.
|
||||
/// Return false if error is thrown.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostFcb::Create(DWORD, BOOL bForce)
|
||||
bool CHostFcb::Create(DWORD, bool bForce)
|
||||
{
|
||||
ASSERT((Human68k::AT_DIRECTORY | Human68k::AT_VOLUME) == 0);
|
||||
ASSERT(strlen(m_szFilename) > 0);
|
||||
ASSERT(m_pFile == nullptr);
|
||||
|
||||
// Duplication check
|
||||
if (bForce == FALSE) {
|
||||
if (!bForce) {
|
||||
struct stat sb; //NOSONAR Cannot be declared in a separate statement because struct keyword is required
|
||||
if (stat(S2U(m_szFilename), &sb) == 0)
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create file
|
||||
|
@ -2316,16 +2301,16 @@ BOOL CHostFcb::Create(DWORD, BOOL bForce)
|
|||
//
|
||||
/// File open
|
||||
///
|
||||
/// Return FALSE if error is thrown.
|
||||
/// Return false if error is thrown.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostFcb::Open()
|
||||
bool CHostFcb::Open()
|
||||
{
|
||||
ASSERT(strlen(m_szFilename) > 0);
|
||||
|
||||
// Fail if directory
|
||||
if (struct stat st; stat(S2U(m_szFilename), &st) == 0 && ((st.st_mode & S_IFMT) == S_IFDIR)) {
|
||||
return FALSE || m_bFlag;
|
||||
return false || m_bFlag;
|
||||
}
|
||||
|
||||
// File open
|
||||
|
@ -2335,23 +2320,6 @@ BOOL CHostFcb::Open()
|
|||
return m_pFile != nullptr || m_bFlag;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
/// File seek
|
||||
///
|
||||
/// Return FALSE if error is thrown.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostFcb::Rewind(DWORD nOffset) const
|
||||
{
|
||||
ASSERT(m_pFile);
|
||||
|
||||
if (fseek(m_pFile, nOffset, SEEK_SET))
|
||||
return FALSE;
|
||||
|
||||
return ftell(m_pFile) != -1L;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
/// Read file
|
||||
|
@ -2396,10 +2364,10 @@ DWORD CHostFcb::Write(const BYTE* pBuffer, DWORD nSize)
|
|||
//
|
||||
/// Truncate file
|
||||
///
|
||||
/// Return FALSE if error is thrown.
|
||||
/// Return false if error is thrown.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostFcb::Truncate() const
|
||||
bool CHostFcb::Truncate() const
|
||||
{
|
||||
ASSERT(m_pFile);
|
||||
|
||||
|
@ -2442,10 +2410,10 @@ DWORD CHostFcb::Seek(DWORD nOffset, DWORD nHumanSeek)
|
|||
//
|
||||
/// Set file time stamp
|
||||
///
|
||||
/// Return FALSE if error is thrown.
|
||||
/// Return false if error is thrown.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostFcb::TimeStamp(DWORD nHumanTime) const
|
||||
bool CHostFcb::TimeStamp(DWORD nHumanTime) const
|
||||
{
|
||||
ASSERT(m_pFile || m_bFlag);
|
||||
|
||||
|
@ -2458,7 +2426,7 @@ BOOL CHostFcb::TimeStamp(DWORD nHumanTime) const
|
|||
t.tm_sec = (nHumanTime & 31) << 1;
|
||||
time_t ti = mktime(&t);
|
||||
if (ti == (time_t)-1)
|
||||
return FALSE;
|
||||
return false;
|
||||
utimbuf ut;
|
||||
ut.actime = ti;
|
||||
ut.modtime = ti;
|
||||
|
@ -2474,21 +2442,17 @@ BOOL CHostFcb::TimeStamp(DWORD nHumanTime) const
|
|||
//
|
||||
/// File close
|
||||
///
|
||||
/// Return FALSE if error is thrown.
|
||||
/// Return false if error is thrown.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CHostFcb::Close()
|
||||
void CHostFcb::Close()
|
||||
{
|
||||
BOOL bResult = TRUE;
|
||||
|
||||
// File close
|
||||
// Always initialize because of the Close→Free (internally one more Close) flow.
|
||||
if (m_pFile) {
|
||||
fclose(m_pFile);
|
||||
m_pFile = nullptr;
|
||||
}
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -2547,8 +2511,8 @@ CHostFcb* CHostFcbManager::Alloc(DWORD nKey)
|
|||
auto p = (ring_t*)m_cRing.Prev();
|
||||
|
||||
// Error if in use (just in case)
|
||||
if (p->f.isSameKey(0) == FALSE) {
|
||||
ASSERT(FALSE);
|
||||
if (!p->f.isSameKey(0)) {
|
||||
ASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -2711,7 +2675,7 @@ int CFileSys::CheckDir(DWORD nUnit, const Human68k::namests_t* pNamests) const
|
|||
if (f.isRootPath())
|
||||
return 0;
|
||||
f.SetPathOnly();
|
||||
if (f.Find(nUnit, &m_cEntry) == FALSE)
|
||||
if (!f.Find(nUnit, &m_cEntry))
|
||||
return FS_DIRNOTFND;
|
||||
|
||||
return 0;
|
||||
|
@ -2745,7 +2709,7 @@ int CFileSys::MakeDir(DWORD nUnit, const Human68k::namests_t* pNamests) const
|
|||
CHostFiles f;
|
||||
f.SetPath(pNamests);
|
||||
f.SetPathOnly();
|
||||
if (f.Find(nUnit, &m_cEntry) == FALSE)
|
||||
if (!f.Find(nUnit, &m_cEntry))
|
||||
return FS_INVALIDPATH;
|
||||
f.AddFilename();
|
||||
|
||||
|
@ -2787,7 +2751,7 @@ int CFileSys::RemoveDir(DWORD nUnit, const Human68k::namests_t* pNamests) const
|
|||
CHostFiles f;
|
||||
f.SetPath(pNamests);
|
||||
f.SetAttribute(Human68k::AT_DIRECTORY);
|
||||
if (f.Find(nUnit, &m_cEntry) == FALSE)
|
||||
if (!f.Find(nUnit, &m_cEntry))
|
||||
return FS_DIRNOTFND;
|
||||
|
||||
// Delete cache
|
||||
|
@ -2837,13 +2801,13 @@ int CFileSys::Rename(DWORD nUnit, const Human68k::namests_t* pNamests, const Hum
|
|||
CHostFiles f;
|
||||
f.SetPath(pNamests);
|
||||
f.SetAttribute(Human68k::AT_ALL);
|
||||
if (f.Find(nUnit, &m_cEntry) == FALSE)
|
||||
if (!f.Find(nUnit, &m_cEntry))
|
||||
return FS_FILENOTFND;
|
||||
|
||||
CHostFiles fNew;
|
||||
fNew.SetPath(pNamestsNew);
|
||||
fNew.SetPathOnly();
|
||||
if (fNew.Find(nUnit, &m_cEntry) == FALSE)
|
||||
if (!fNew.Find(nUnit, &m_cEntry))
|
||||
return FS_INVALIDPATH;
|
||||
fNew.AddFilename();
|
||||
|
||||
|
@ -2894,7 +2858,7 @@ int CFileSys::Delete(DWORD nUnit, const Human68k::namests_t* pNamests) const
|
|||
// Generate path name
|
||||
CHostFiles f;
|
||||
f.SetPath(pNamests);
|
||||
if (f.Find(nUnit, &m_cEntry) == FALSE)
|
||||
if (!f.Find(nUnit, &m_cEntry))
|
||||
return FS_FILENOTFND;
|
||||
|
||||
// Delete file
|
||||
|
@ -2930,7 +2894,7 @@ int CFileSys::Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD
|
|||
CHostFiles f;
|
||||
f.SetPath(pNamests);
|
||||
f.SetAttribute(Human68k::AT_ALL);
|
||||
if (f.Find(nUnit, &m_cEntry) == FALSE)
|
||||
if (!f.Find(nUnit, &m_cEntry))
|
||||
return FS_FILENOTFND;
|
||||
|
||||
// Exit if attribute is acquired
|
||||
|
@ -2966,7 +2930,7 @@ int CFileSys::Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD
|
|||
m_cEntry.CleanCache(nUnit, f.GetHumanPath());
|
||||
|
||||
// Get attribute after changing
|
||||
if (f.Find(nUnit, &m_cEntry) == FALSE)
|
||||
if (!f.Find(nUnit, &m_cEntry))
|
||||
return FS_FILENOTFND;
|
||||
|
||||
return f.GetAttribute();
|
||||
|
@ -3006,11 +2970,11 @@ int CFileSys::Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests
|
|||
// Path check
|
||||
CHostFiles f;
|
||||
f.SetPath(pNamests);
|
||||
if (f.isRootPath() == FALSE)
|
||||
if (!f.isRootPath())
|
||||
return FS_FILENOTFND;
|
||||
|
||||
// Immediately return the results without allocating buffer
|
||||
if (FilesVolume(nUnit, pFiles) == FALSE)
|
||||
if (!FilesVolume(nUnit, pFiles))
|
||||
return FS_FILENOTFND;
|
||||
return 0;
|
||||
}
|
||||
|
@ -3026,9 +2990,9 @@ int CFileSys::Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests
|
|||
|
||||
// Directory check
|
||||
pHostFiles->SetPath(pNamests);
|
||||
if (pHostFiles->isRootPath() == FALSE) {
|
||||
if (!pHostFiles->isRootPath()) {
|
||||
pHostFiles->SetPathOnly();
|
||||
if (pHostFiles->Find(nUnit, &m_cEntry) == FALSE) {
|
||||
if (!pHostFiles->Find(nUnit, &m_cEntry)) {
|
||||
m_cFiles.Free(pHostFiles);
|
||||
return FS_DIRNOTFND;
|
||||
}
|
||||
|
@ -3039,7 +3003,7 @@ int CFileSys::Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests
|
|||
pHostFiles->SetAttribute(pFiles->fatr);
|
||||
|
||||
// Find file
|
||||
if (pHostFiles->Find(nUnit, &m_cEntry) == FALSE) {
|
||||
if (!pHostFiles->Find(nUnit, &m_cEntry)) {
|
||||
m_cFiles.Free(pHostFiles);
|
||||
return FS_FILENOTFND;
|
||||
}
|
||||
|
@ -3055,12 +3019,6 @@ int CFileSys::Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests
|
|||
pFiles->sector = nKey;
|
||||
pFiles->offset = 0;
|
||||
|
||||
// When the file name does not include wildcards, the buffer may be released
|
||||
if (pNamests->wildcard == 0) {
|
||||
// However, there is a chance the virtual selector may be used for emulation, so don't release immediately
|
||||
// m_cFiles.Free(pHostFiles);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3090,7 +3048,7 @@ int CFileSys::NFiles(DWORD nUnit, DWORD nKey, Human68k::files_t* pFiles)
|
|||
return FS_INVALIDPTR;
|
||||
|
||||
// Find file
|
||||
if (pHostFiles->Find(nUnit, &m_cEntry) == FALSE) {
|
||||
if (!pHostFiles->Find(nUnit, &m_cEntry)) {
|
||||
m_cFiles.Free(pHostFiles);
|
||||
return FS_FILENOTFND;
|
||||
}
|
||||
|
@ -3113,7 +3071,7 @@ int CFileSys::NFiles(DWORD nUnit, DWORD nKey, Human68k::files_t* pFiles)
|
|||
/// $49 - Create new file
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, DWORD nHumanAttribute, BOOL bForce)
|
||||
int CFileSys::Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, DWORD nHumanAttribute, bool bForce)
|
||||
{
|
||||
ASSERT(pNamests);
|
||||
ASSERT(nKey);
|
||||
|
@ -3142,7 +3100,7 @@ int CFileSys::Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamest
|
|||
CHostFiles f;
|
||||
f.SetPath(pNamests);
|
||||
f.SetPathOnly();
|
||||
if (f.Find(nUnit, &m_cEntry) == FALSE)
|
||||
if (!f.Find(nUnit, &m_cEntry))
|
||||
return FS_INVALIDPATH;
|
||||
f.AddFilename();
|
||||
|
||||
|
@ -3159,13 +3117,13 @@ int CFileSys::Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamest
|
|||
|
||||
// Set open mode
|
||||
pFcb->mode = (WORD)((pFcb->mode & ~Human68k::OP_MASK) | Human68k::OP_FULL);
|
||||
if (pHostFcb->SetMode(pFcb->mode) == FALSE) {
|
||||
if (!pHostFcb->SetMode(pFcb->mode)) {
|
||||
m_cFcb.Free(pHostFcb);
|
||||
return FS_ILLEGALMOD;
|
||||
}
|
||||
|
||||
// Create file
|
||||
if (pHostFcb->Create(nHumanAttribute, bForce) == FALSE) {
|
||||
if (!pHostFcb->Create(nHumanAttribute, bForce)) {
|
||||
m_cFcb.Free(pHostFcb);
|
||||
return FS_FILEEXIST;
|
||||
}
|
||||
|
@ -3215,7 +3173,7 @@ int CFileSys::Open(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests,
|
|||
CHostFiles f;
|
||||
f.SetPath(pNamests);
|
||||
f.SetAttribute(Human68k::AT_ALL);
|
||||
if (f.Find(nUnit, &m_cEntry) == FALSE)
|
||||
if (!f.Find(nUnit, &m_cEntry))
|
||||
return FS_FILENOTFND;
|
||||
|
||||
// Time stamp
|
||||
|
@ -3233,13 +3191,13 @@ int CFileSys::Open(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests,
|
|||
pHostFcb->SetHumanPath(f.GetHumanPath());
|
||||
|
||||
// Set open mode
|
||||
if (pHostFcb->SetMode(pFcb->mode) == FALSE) {
|
||||
if (!pHostFcb->SetMode(pFcb->mode)) {
|
||||
m_cFcb.Free(pHostFcb);
|
||||
return FS_ILLEGALMOD;
|
||||
}
|
||||
|
||||
// File open
|
||||
if (pHostFcb->Open() == FALSE) {
|
||||
if (!pHostFcb->Open()) {
|
||||
m_cFcb.Free(pHostFcb);
|
||||
return FS_INVALIDPATH;
|
||||
}
|
||||
|
@ -3345,7 +3303,7 @@ int CFileSys::Write(DWORD nKey, Human68k::fcb_t* pFcb, const BYTE* pBuffer, DWOR
|
|||
DWORD nResult;
|
||||
if (nSize == 0) {
|
||||
// Truncate
|
||||
if (pHostFcb->Truncate() == FALSE) {
|
||||
if (!pHostFcb->Truncate()) {
|
||||
m_cFcb.Free(pHostFcb);
|
||||
return FS_CANTSEEK;
|
||||
}
|
||||
|
@ -3453,7 +3411,7 @@ DWORD CFileSys::TimeStamp(DWORD nUnit, DWORD nKey, Human68k::fcb_t* pFcb, DWORD
|
|||
return FS_NOTOPENED;
|
||||
|
||||
// Set time stamp
|
||||
if (pHostFcb->TimeStamp(nHumanTime) == FALSE) {
|
||||
if (!pHostFcb->TimeStamp(nHumanTime)) {
|
||||
m_cFcb.Free(pHostFcb);
|
||||
return FS_INVALIDPRM;
|
||||
}
|
||||
|
@ -3552,9 +3510,9 @@ int CFileSys::GetDPB(DWORD nUnit, Human68k::dpb_t* pDpb) const
|
|||
media = m_cEntry.GetMediaByte(nUnit);
|
||||
|
||||
// Acquire sector data
|
||||
if (m_cEntry.GetCapacityCache(nUnit, &cap) == FALSE) {
|
||||
if (!m_cEntry.GetCapacityCache(nUnit, &cap)) {
|
||||
// Carry out an extra media check here because it may be skipped when doing a manual eject
|
||||
if (m_cEntry.isEnable(nUnit) == FALSE)
|
||||
if (!m_cEntry.isEnable(nUnit))
|
||||
goto none;
|
||||
|
||||
// Media check
|
||||
|
@ -3638,7 +3596,7 @@ int CFileSys::DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize)
|
|||
|
||||
// Acquire sector data
|
||||
Human68k::capacity_t cap;
|
||||
if (m_cEntry.GetCapacityCache(nUnit, &cap) == FALSE) {
|
||||
if (!m_cEntry.GetCapacityCache(nUnit, &cap)) {
|
||||
// Get drive status
|
||||
m_cEntry.GetCapacity(nUnit, &cap);
|
||||
}
|
||||
|
@ -3680,7 +3638,7 @@ int CFileSys::DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize)
|
|||
CHostFcb f;
|
||||
f.SetFilename(pHostFiles->GetPath());
|
||||
f.SetMode(Human68k::OP_READ);
|
||||
if (f.Open() == FALSE)
|
||||
if (!f.Open())
|
||||
return FS_INVALIDPRM;
|
||||
memset(pBuffer, 0, 0x200);
|
||||
DWORD nResult = f.Read(pBuffer, 0x200);
|
||||
|
@ -3793,7 +3751,6 @@ int CFileSys::Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl)
|
|||
//---------------------------------------------------------------------------
|
||||
int CFileSys::Flush(DWORD nUnit) const
|
||||
{
|
||||
|
||||
// Unit check
|
||||
if (nUnit >= CHostEntry::DRIVE_MAX)
|
||||
return FS_FATAL_INVALIDUNIT;
|
||||
|
@ -3811,7 +3768,6 @@ int CFileSys::Flush(DWORD nUnit) const
|
|||
//---------------------------------------------------------------------------
|
||||
int CFileSys::CheckMedia(DWORD nUnit) const
|
||||
{
|
||||
|
||||
// Unit check
|
||||
if (nUnit >= CHostEntry::DRIVE_MAX)
|
||||
return FS_FATAL_INVALIDUNIT;
|
||||
|
@ -3820,7 +3776,7 @@ int CFileSys::CheckMedia(DWORD nUnit) const
|
|||
|
||||
// Media change check
|
||||
// Throw error when media is not inserted
|
||||
if (BOOL bResult = m_cEntry.CheckMedia(nUnit); bResult == FALSE) {
|
||||
if (!m_cEntry.CheckMedia(nUnit)) {
|
||||
return FS_INVALIDFUNC;
|
||||
}
|
||||
|
||||
|
@ -3834,7 +3790,6 @@ int CFileSys::CheckMedia(DWORD nUnit) const
|
|||
//---------------------------------------------------------------------------
|
||||
int CFileSys::Lock(DWORD nUnit) const
|
||||
{
|
||||
|
||||
// Unit check
|
||||
if (nUnit >= CHostEntry::DRIVE_MAX)
|
||||
return FS_FATAL_INVALIDUNIT;
|
||||
|
@ -3857,7 +3812,6 @@ int CFileSys::Lock(DWORD nUnit) const
|
|||
//---------------------------------------------------------------------------
|
||||
void CFileSys::SetOption(DWORD nOption)
|
||||
{
|
||||
|
||||
// Clear cache when option settings change
|
||||
if (m_nOption ^ nOption)
|
||||
m_cEntry.CleanCache();
|
||||
|
@ -3957,26 +3911,26 @@ void CFileSys::InitOption(const Human68k::argument_t* pArgument)
|
|||
/// Get volume label
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL CFileSys::FilesVolume(DWORD nUnit, Human68k::files_t* pFiles) const
|
||||
bool CFileSys::FilesVolume(DWORD nUnit, Human68k::files_t* pFiles) const
|
||||
{
|
||||
ASSERT(pFiles);
|
||||
|
||||
// Get volume label
|
||||
TCHAR szVolume[32];
|
||||
if (BOOL bResult = m_cEntry.GetVolumeCache(nUnit, szVolume); bResult == FALSE) {
|
||||
if (bool bResult = m_cEntry.GetVolumeCache(nUnit, szVolume); !bResult) {
|
||||
// Carry out an extra media check here because it may be skipped when doing a manual eject
|
||||
if (m_cEntry.isEnable(nUnit) == FALSE)
|
||||
return FALSE;
|
||||
if (!m_cEntry.isEnable(nUnit))
|
||||
return false;
|
||||
|
||||
// Media check
|
||||
if (m_cEntry.isMediaOffline(nUnit))
|
||||
return FALSE;
|
||||
return false;
|
||||
|
||||
// Get volume label
|
||||
m_cEntry.GetVolume(nUnit, szVolume);
|
||||
}
|
||||
if (szVolume[0] == _T('\0'))
|
||||
return FALSE;
|
||||
return false;
|
||||
|
||||
pFiles->attr = Human68k::AT_VOLUME;
|
||||
pFiles->time = 0;
|
||||
|
@ -3988,5 +3942,5 @@ BOOL CFileSys::FilesVolume(DWORD nUnit, Human68k::files_t* pFiles) const
|
|||
fname.ConvertHuman();
|
||||
strcpy((char*)pFiles->full, (const char*)fname.GetHuman());
|
||||
|
||||
return TRUE;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -451,8 +451,8 @@ public:
|
|||
const TCHAR* GetHost() const { return m_szHost; } ///< Get the name of the host
|
||||
void ConvertHuman(int nCount = -1); ///< Convert the Human68k name
|
||||
void CopyHuman(const BYTE* szHuman); ///< Copy the Human68k name
|
||||
BOOL isReduce() const; ///< Inspect if the Human68k name is generated
|
||||
BOOL isCorrect() const { return m_bCorrect; } ///< Inspect if the Human68k file name adhers to naming rules
|
||||
bool isReduce() const; ///< Inspect if the Human68k name is generated
|
||||
bool isCorrect() const { return m_bCorrect; } ///< Inspect if the Human68k file name adhers to naming rules
|
||||
const BYTE* GetHuman() const { return m_szHuman; } ///< Get Human68k file name
|
||||
const BYTE* GetHumanLast() const
|
||||
{ return m_pszHumanLast; } ///< Get Human68k file name
|
||||
|
@ -470,9 +470,9 @@ public:
|
|||
{ m_dirHuman.cluster = nHumanCluster; } ///< Set Human68k directory entry
|
||||
const Human68k::dirent_t* GetEntry() const
|
||||
{ return &m_dirHuman; } ///< Get Human68k directory entry
|
||||
BOOL CheckAttribute(DWORD nHumanAttribute) const; ///< Determine Human68k directory entry attributes
|
||||
BOOL isSameEntry(const Human68k::dirent_t* pdirHuman) const
|
||||
{ ASSERT(pdirHuman); return memcmp(&m_dirHuman, pdirHuman, sizeof(m_dirHuman)) == 0; }
|
||||
int CheckAttribute(DWORD nHumanAttribute) const; ///< Determine Human68k directory entry attributes
|
||||
bool isSameEntry(const Human68k::dirent_t* pdirHuman) const
|
||||
{ assert(pdirHuman); return memcmp(&m_dirHuman, pdirHuman, sizeof(m_dirHuman)) == 0; }
|
||||
///< Determine Human68k directory entry match
|
||||
|
||||
// Path name operations
|
||||
|
@ -484,7 +484,7 @@ private:
|
|||
|
||||
const BYTE* m_pszHumanLast = nullptr; ///< Last position of the Human68k internal name of the relevant entry
|
||||
const BYTE* m_pszHumanExt = nullptr; ///< Position of the extension of the Human68k internal name of the relevant entry
|
||||
BOOL m_bCorrect = FALSE; ///< TRUE if the relevant entry of the Human68k internal name is correct
|
||||
bool m_bCorrect = false; ///< TRUE if the relevant entry of the Human68k internal name is correct
|
||||
BYTE m_szHuman[24]; ///< Human68k internal name of the relevant entry
|
||||
Human68k::dirent_t m_dirHuman; ///< All information for the Human68k relevant entry
|
||||
TCHAR m_szHost[FILEPATH_MAX]; ///< The host name of the relevant entry (variable length)
|
||||
|
@ -535,35 +535,35 @@ public:
|
|||
CHostPath(CHostPath&) = delete;
|
||||
CHostPath& operator=(const CHostPath&) = delete;
|
||||
|
||||
void Clean(); ///< Initialialize for reuse
|
||||
void Clean(); ///< Initialialize for reuse
|
||||
|
||||
void SetHuman(const BYTE* szHuman); ///< Directly specify the name on the Human68k side
|
||||
void SetHost(const TCHAR* szHost); ///< Directly specify the name on the host side
|
||||
BOOL isSameHuman(const BYTE* szHuman) const; ///< Compare the name on the Human68k side
|
||||
BOOL isSameChild(const BYTE* szHuman) const; ///< Compare the name on the Human68k side
|
||||
const TCHAR* GetHost() const { return m_szHost; } ///< Obtain the name on the host side
|
||||
const CHostFilename* FindFilename(const BYTE* szHuman, DWORD nHumanAttribute = Human68k::AT_ALL) const;
|
||||
void SetHuman(const BYTE* szHuman); ///< Directly specify the name on the Human68k side
|
||||
void SetHost(const TCHAR* szHost); ///< Directly specify the name on the host side
|
||||
bool isSameHuman(const BYTE* szHuman) const; ///< Compare the name on the Human68k side
|
||||
bool isSameChild(const BYTE* szHuman) const; ///< Compare the name on the Human68k side
|
||||
const TCHAR* GetHost() const { return m_szHost; } ///< Obtain the name on the host side
|
||||
const CHostFilename* FindFilename(const BYTE* szHuman, DWORD nHumanAttribute = Human68k::AT_ALL) const;
|
||||
///< Find file name
|
||||
const CHostFilename* FindFilenameWildcard(const BYTE* szHuman, DWORD nHumanAttribute, find_t* pFind) const;
|
||||
const CHostFilename* FindFilenameWildcard(const BYTE* szHuman, DWORD nHumanAttribute, find_t* pFind) const;
|
||||
///< Find file name (with support for wildcards)
|
||||
BOOL isRefresh() const; ///< Check that the file change has been done
|
||||
void Refresh(); ///< Refresh file
|
||||
void Backup(); /// Backup the time stamp on the host side
|
||||
void Restore() const; /// Restore the time stamp on the host side
|
||||
void Release(); ///< Update
|
||||
bool isRefresh() const; ///< Check that the file change has been done
|
||||
void Refresh(); ///< Refresh file
|
||||
void Backup(); /// Backup the time stamp on the host side
|
||||
void Restore() const; /// Restore the time stamp on the host side
|
||||
void Release(); ///< Update
|
||||
|
||||
// CHostEntry is an external API that we use
|
||||
static void InitId() { g_nId = 0; } ///< Initialize the counter for the unique ID generation
|
||||
static void InitId() { g_nId = 0; } ///< Initialize the counter for the unique ID generation
|
||||
|
||||
private:
|
||||
static ring_t* Alloc(size_t nLength); ///< Allocate memory for the file name
|
||||
static void Free(ring_t* pRing); ///< Release memory for the file name
|
||||
static int Compare(const BYTE* pFirst, const BYTE* pLast, const BYTE* pBufFirst, const BYTE* pBufLast);
|
||||
static ring_t* Alloc(size_t nLength); ///< Allocate memory for the file name
|
||||
static void Free(ring_t* pRing); ///< Release memory for the file name
|
||||
static int Compare(const BYTE* pFirst, const BYTE* pLast, const BYTE* pBufFirst, const BYTE* pBufLast);
|
||||
///< Compare string (with support for wildcards)
|
||||
|
||||
CRing m_cRing; ///< For CHostFilename linking
|
||||
time_t m_tBackup = FALSE; ///< For time stamp restoration
|
||||
BOOL m_bRefresh = TRUE; ///< Refresh flag
|
||||
time_t m_tBackup = 0; ///< For time stamp restoration
|
||||
bool m_bRefresh = true; ///< Refresh flag
|
||||
DWORD m_nId = 0; ///< Unique ID (When the value has changed, it means an update has been made)
|
||||
BYTE m_szHuman[HUMAN68K_PATH_MAX]; ///< The internal Human68k name for the relevant entry
|
||||
TCHAR m_szHost[FILEPATH_MAX]; ///< The host side name for the relevant entry
|
||||
|
@ -602,14 +602,14 @@ public:
|
|||
void Init();
|
||||
|
||||
void SetKey(DWORD nKey) { m_nKey = nKey; } ///< Set search key
|
||||
BOOL isSameKey(DWORD nKey) const { return m_nKey == nKey; } ///< Compare search key
|
||||
bool isSameKey(DWORD nKey) const { return m_nKey == nKey; } ///< Compare search key
|
||||
void SetPath(const Human68k::namests_t* pNamests); ///< Create path and file name internally
|
||||
BOOL isRootPath() const { return m_szHumanPath[1] == '\0'; } ///< Check if root directory
|
||||
bool isRootPath() const { return m_szHumanPath[1] == '\0'; } ///< Check if root directory
|
||||
void SetPathWildcard() { m_nHumanWildcard = 1; } ///< Enable file search using wildcards
|
||||
void SetPathOnly() { m_nHumanWildcard = 0xFF; } ///< Enable only path names
|
||||
BOOL isPathOnly() const { return m_nHumanWildcard == 0xFF; } ///< Check if set to only path names
|
||||
bool isPathOnly() const { return m_nHumanWildcard == 0xFF; } ///< Check if set to only path names
|
||||
void SetAttribute(DWORD nHumanAttribute) { m_nHumanAttribute = nHumanAttribute; } ///< Set search attribute
|
||||
BOOL Find(DWORD nUnit, const class CHostEntry* pEntry); ///< Find files on the Human68k side, generating data on the host side
|
||||
bool Find(DWORD nUnit, const class CHostEntry* pEntry); ///< Find files on the Human68k side, generating data on the host side
|
||||
const CHostFilename* Find(const CHostPath* pPath); ///< Find file name
|
||||
void SetEntry(const CHostFilename* pFilename); ///< Store search results on the Human68k side
|
||||
void SetResult(const TCHAR* szPath); ///< Set names on the host side
|
||||
|
@ -681,27 +681,26 @@ public:
|
|||
void Init();
|
||||
|
||||
void SetKey(DWORD nKey) { m_nKey = nKey; } ///< Set search key
|
||||
BOOL isSameKey(DWORD nKey) const { return m_nKey == nKey; } ///< Compare search key
|
||||
void SetUpdate() { m_bUpdate = TRUE; } ///< Update
|
||||
BOOL isUpdate() const { return m_bUpdate; } ///< Get update state
|
||||
BOOL SetMode(DWORD nHumanMode); ///< Set file open mode
|
||||
bool isSameKey(DWORD nKey) const { return m_nKey == nKey; } ///< Compare search key
|
||||
void SetUpdate() { m_bUpdate = true; } ///< Update
|
||||
bool isUpdate() const { return m_bUpdate; } ///< Get update state
|
||||
bool SetMode(DWORD nHumanMode); ///< Set file open mode
|
||||
void SetFilename(const TCHAR* szFilename); ///< Set file name
|
||||
void SetHumanPath(const BYTE* szHumanPath); ///< Set Human68k path name
|
||||
const BYTE* GetHumanPath() const { return m_szHumanPath; } ///< Get Human68k path name
|
||||
|
||||
BOOL Create(DWORD nHumanAttribute, BOOL bForce); ///< Create file
|
||||
BOOL Open(); ///< Open file
|
||||
BOOL Rewind(DWORD nOffset) const; ///< Seek file
|
||||
bool Create(DWORD nHumanAttribute, bool bForce); ///< Create file
|
||||
bool Open(); ///< Open file
|
||||
DWORD Read(BYTE* pBuffer, DWORD nSize); ///< Read file
|
||||
DWORD Write(const BYTE* pBuffer, DWORD nSize); ///< Write file
|
||||
BOOL Truncate() const; ///< Truncate file
|
||||
bool Truncate() const; ///< Truncate file
|
||||
DWORD Seek(DWORD nOffset, DWORD nHumanSeek); ///< Seek file
|
||||
BOOL TimeStamp(DWORD nHumanTime) const; ///< Set file time stamp
|
||||
BOOL Close(); ///< Close file
|
||||
bool TimeStamp(DWORD nHumanTime) const; ///< Set file time stamp
|
||||
void Close(); ///< Close file
|
||||
|
||||
private:
|
||||
DWORD m_nKey = 0; ///< Human68k FCB buffer address (0 if unused)
|
||||
BOOL m_bUpdate = FALSE; ///< Update flag
|
||||
bool m_bUpdate = false; ///< Update flag
|
||||
FILE* m_pFile = nullptr; ///< Host side file object
|
||||
const char* m_pszMode = nullptr; ///< Host side file open mode
|
||||
bool m_bFlag = false; ///< Host side file open flag
|
||||
|
@ -753,19 +752,19 @@ public:
|
|||
|
||||
void Init(const TCHAR* szBase, DWORD nFlag); ///< Initialization (device startup and load)
|
||||
|
||||
BOOL isWriteProtect() const { return m_bWriteProtect; }
|
||||
BOOL isEnable() const { return m_bEnable; } ///< Is it accessible?
|
||||
BOOL isMediaOffline() const;
|
||||
bool isWriteProtect() const { return m_bWriteProtect; }
|
||||
bool isEnable() const { return m_bEnable; } ///< Is it accessible?
|
||||
bool isMediaOffline() const;
|
||||
BYTE GetMediaByte() const;
|
||||
DWORD GetStatus() const;
|
||||
void SetEnable(BOOL bEnable); ///< Set media status
|
||||
BOOL CheckMedia(); ///< Check if media was changed
|
||||
void SetEnable(bool); ///< Set media status
|
||||
bool CheckMedia(); ///< Check if media was changed
|
||||
void Update(); ///< Update media status
|
||||
void Eject();
|
||||
void GetVolume(TCHAR* szLabel); ///< Get volume label
|
||||
BOOL GetVolumeCache(TCHAR* szLabel) const; ///< Get volume label from cache
|
||||
bool GetVolumeCache(TCHAR* szLabel) const; ///< Get volume label from cache
|
||||
DWORD GetCapacity(Human68k::capacity_t* pCapacity);
|
||||
BOOL GetCapacityCache(Human68k::capacity_t* pCapacity) const; ///< Get capacity from cache
|
||||
bool GetCapacityCache(Human68k::capacity_t* pCapacity) const; ///< Get capacity from cache
|
||||
|
||||
// Cache operations
|
||||
void CleanCache() const; ///< Update all cache
|
||||
|
@ -775,7 +774,7 @@ public:
|
|||
CHostPath* FindCache(const BYTE* szHuman); ///< Inspect if the specified path is cached
|
||||
CHostPath* CopyCache(CHostFiles* pFiles); ///< Acquire the host side name on the basis of cache information
|
||||
CHostPath* MakeCache(CHostFiles* pFiles); ///< Get all required data to construct a host side name
|
||||
BOOL Find(CHostFiles* pFiles); ///< Find host side name (path + file name (can be abbreviated) + attribute)
|
||||
bool Find(CHostFiles* pFiles); ///< Find host side name (path + file name (can be abbreviated) + attribute)
|
||||
|
||||
private:
|
||||
// Path name operations
|
||||
|
@ -788,12 +787,12 @@ private:
|
|||
CHostPath f;
|
||||
};
|
||||
|
||||
BOOL m_bWriteProtect = FALSE; ///< TRUE if write-protected
|
||||
BOOL m_bEnable = FALSE; ///< TRUE if media is usable
|
||||
bool m_bWriteProtect = false; ///< TRUE if write-protected
|
||||
bool m_bEnable = false; ///< TRUE if media is usable
|
||||
DWORD m_nRing = 0; ///< Number of stored path names
|
||||
CRing m_cRing; ///< For attaching to CHostPath
|
||||
Human68k::capacity_t m_capCache; ///< Sector data cache: if "sectors == 0" then not cached
|
||||
BOOL m_bVolumeCache = FALSE; ///< TRUE if the volume label has been read
|
||||
bool m_bVolumeCache = false; ///< TRUE if the volume label has been read
|
||||
TCHAR m_szVolumeCache[24] = {}; ///< Volume label cache
|
||||
TCHAR m_szBase[FILEPATH_MAX] = {}; ///< Base path
|
||||
};
|
||||
|
@ -824,22 +823,22 @@ public:
|
|||
void CleanCache(DWORD nUnit, const BYTE* szHumanPath) const; ///< Update cache for the specified path
|
||||
void CleanCacheChild(DWORD nUnit, const BYTE* szHumanPath) const; ///< Update cache below the specified path
|
||||
void DeleteCache(DWORD nUnit, const BYTE* szHumanPath) const; ///< Delete cache for the specified path
|
||||
BOOL Find(DWORD nUnit, CHostFiles* pFiles) const; ///< Find host side name (path + file name (can be abbreviated) + attribute)
|
||||
bool Find(DWORD nUnit, CHostFiles* pFiles) const; ///< Find host side name (path + file name (can be abbreviated) + attribute)
|
||||
void ShellNotify(DWORD nEvent, const TCHAR* szPath); ///< Notify status change in the host side file system
|
||||
|
||||
// Drive object operations
|
||||
void SetDrv(DWORD nUnit, CHostDrv* pDrv);
|
||||
BOOL isWriteProtect(DWORD nUnit) const;
|
||||
BOOL isEnable(DWORD nUnit) const; ///< Is it accessible?
|
||||
BOOL isMediaOffline(DWORD nUnit) const;
|
||||
bool isWriteProtect(DWORD nUnit) const;
|
||||
bool isEnable(DWORD nUnit) const; ///< Is it accessible?
|
||||
bool isMediaOffline(DWORD nUnit) const;
|
||||
BYTE GetMediaByte(DWORD nUnit) const;
|
||||
DWORD GetStatus(DWORD nUnit) const; ///< Get drive status
|
||||
BOOL CheckMedia(DWORD nUnit) const; ///< Media change check
|
||||
bool CheckMedia(DWORD nUnit) const; ///< Media change check
|
||||
void Eject(DWORD nUnit) const;
|
||||
void GetVolume(DWORD nUnit, TCHAR* szLabel) const; ///< Get volume label
|
||||
BOOL GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const; ///< Get volume label from cache
|
||||
bool GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const; ///< Get volume label from cache
|
||||
DWORD GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity) const;
|
||||
BOOL GetCapacityCache(DWORD nUnit, Human68k::capacity_t* pCapacity) const; ///< Get cluster size from cache
|
||||
bool GetCapacityCache(DWORD nUnit, Human68k::capacity_t* pCapacity) const; ///< Get cluster size from cache
|
||||
|
||||
private:
|
||||
|
||||
|
@ -900,7 +899,7 @@ public:
|
|||
int Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::files_t* pFiles);
|
||||
///< $47 - Find file
|
||||
int NFiles(DWORD nUnit, DWORD nKey, Human68k::files_t* pFiles); ///< $48 - Find next file
|
||||
int Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, DWORD nHumanAttribute, BOOL bForce);
|
||||
int Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, DWORD nHumanAttribute, bool bForce);
|
||||
///< $49 - Create file
|
||||
int Open(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb);
|
||||
///< $4A - Open file
|
||||
|
@ -927,13 +926,11 @@ public:
|
|||
DWORD GetDefault() const { return m_nOptionDefault; } ///< Get default options
|
||||
static DWORD GetFileOption() { return g_nOption; } ///< Get file name change option
|
||||
|
||||
enum {
|
||||
DriveMax = CHostEntry::DRIVE_MAX ///< Max number of drive candidates
|
||||
};
|
||||
static const int DriveMax = CHostEntry::DRIVE_MAX; ///< Max number of drive candidates
|
||||
|
||||
private:
|
||||
void InitOption(const Human68k::argument_t* pArgument);
|
||||
BOOL FilesVolume(DWORD nUnit, Human68k::files_t* pFiles) const; ///< Get volume label
|
||||
void InitOption(const Human68k::argument_t* pArgument);
|
||||
bool FilesVolume(DWORD nUnit, Human68k::files_t* pFiles) const; ///< Get volume label
|
||||
|
||||
DWORD m_nUnits = 0; ///< Number of current drive objects (Changes for every resume)
|
||||
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
#include "rascsi_exceptions.h"
|
||||
#include <sstream>
|
||||
|
||||
static const char *BRIDGE_NAME = "rascsi_bridge";
|
||||
|
||||
using namespace std;
|
||||
using namespace ras_util;
|
||||
|
||||
|
@ -39,7 +37,7 @@ static bool br_setif(int br_socket_fd, const char* bridgename, const char* ifnam
|
|||
struct ifreq ifr;
|
||||
ifr.ifr_ifindex = if_nametoindex(ifname);
|
||||
if (ifr.ifr_ifindex == 0) {
|
||||
LOGERROR("Can't if_nametoindex: %s", strerror(errno))
|
||||
LOGERROR("Can't if_nametoindex %s: %s", ifname, strerror(errno))
|
||||
return false;
|
||||
}
|
||||
strncpy(ifr.ifr_name, bridgename, IFNAMSIZ - 1);
|
||||
|
@ -118,14 +116,14 @@ bool CTapDriver::Init(const unordered_map<string, string>& const_params)
|
|||
return false;
|
||||
}
|
||||
|
||||
LOGTRACE("Opened tap device %d",m_hTAP)
|
||||
LOGTRACE("Opened tap device %d", m_hTAP)
|
||||
|
||||
// IFF_NO_PI for no extra packet information
|
||||
struct ifreq ifr;
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
char dev[IFNAMSIZ] = "ras0";
|
||||
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
|
||||
string dev = "ras0";
|
||||
strncpy(ifr.ifr_name, dev.c_str(), IFNAMSIZ - 1);
|
||||
|
||||
LOGTRACE("Going to open %s", ifr.ifr_name)
|
||||
|
||||
|
@ -325,7 +323,7 @@ bool CTapDriver::Init(const unordered_map<string, string>& const_params)
|
|||
LOGTRACE("Got the MAC")
|
||||
|
||||
// Save MAC address
|
||||
memcpy(m_MacAddr, ifr.ifr_hwaddr.sa_data, sizeof(m_MacAddr));
|
||||
memcpy(m_MacAddr.data(), ifr.ifr_hwaddr.sa_data, m_MacAddr.size());
|
||||
|
||||
close(ip_fd);
|
||||
close(br_socket_fd);
|
||||
|
@ -403,7 +401,8 @@ void CTapDriver::Flush()
|
|||
{
|
||||
LOGTRACE("%s", __PRETTY_FUNCTION__)
|
||||
while(PendingPackets()){
|
||||
(void)Rx(m_garbage_buffer);
|
||||
array<BYTE, ETH_FRAME_LEN> m_garbage_buffer;
|
||||
(void)Rx(m_garbage_buffer.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -411,7 +410,7 @@ void CTapDriver::GetMacAddr(BYTE *mac) const
|
|||
{
|
||||
ASSERT(mac);
|
||||
|
||||
memcpy(mac, m_MacAddr, sizeof(m_MacAddr));
|
||||
memcpy(mac, m_MacAddr.data(), m_MacAddr.size());
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <array>
|
||||
|
||||
#ifndef ETH_FRAME_LEN
|
||||
#define ETH_FRAME_LEN 1514
|
||||
|
@ -32,11 +33,11 @@ using namespace std;
|
|||
//===========================================================================
|
||||
class CTapDriver
|
||||
{
|
||||
private:
|
||||
|
||||
friend class SCSIDaynaPort;
|
||||
friend class SCSIBR;
|
||||
|
||||
static constexpr const char *BRIDGE_NAME = "rascsi_bridge";
|
||||
|
||||
CTapDriver() = default;
|
||||
~CTapDriver() = default;
|
||||
CTapDriver(CTapDriver&) = delete;
|
||||
|
@ -58,10 +59,8 @@ public:
|
|||
void Flush(); // Purge all of the packets that are waiting to be processed
|
||||
|
||||
private:
|
||||
BYTE m_MacAddr[6] = {}; // MAC Address
|
||||
int m_hTAP = -1; // File handle
|
||||
|
||||
BYTE m_garbage_buffer[ETH_FRAME_LEN];
|
||||
array<byte, 6> m_MacAddr; // MAC Address
|
||||
int m_hTAP = -1; // File handle
|
||||
|
||||
pcap_t *m_pcap = nullptr;
|
||||
pcap_dumper_t *m_pcap_dumper = nullptr;
|
||||
|
|
|
@ -13,14 +13,17 @@
|
|||
#include "log.h"
|
||||
#include "rascsi_exceptions.h"
|
||||
#include "device.h"
|
||||
#include <iomanip>
|
||||
|
||||
using namespace std;
|
||||
|
||||
Device::Device(const string& t) : type(t)
|
||||
{
|
||||
assert(type.length() == 4);
|
||||
|
||||
char rev[5];
|
||||
sprintf(rev, "%02d%02d", rascsi_major_version, rascsi_minor_version);
|
||||
revision = rev;
|
||||
ostringstream os;
|
||||
os << setw(2) << setfill('0') << rascsi_major_version << setw(2) << setfill('0') << rascsi_minor_version;
|
||||
revision = os.str();
|
||||
}
|
||||
|
||||
void Device::Reset()
|
||||
|
|
|
@ -71,7 +71,7 @@ class Device
|
|||
// Sense Key
|
||||
// Additional Sense Code (ASC)
|
||||
// LSB Additional Sense Code Qualifier(ASCQ)
|
||||
int status_code = scsi_defs::status::GOOD;
|
||||
int status_code = 0;
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -97,7 +97,7 @@ public:
|
|||
// Override for device specific initializations, to be called after all device properties have been set
|
||||
virtual bool Init(const unordered_map<string, string>&) { return true; };
|
||||
|
||||
virtual bool Dispatch() = 0;
|
||||
virtual bool Dispatch(scsi_defs::scsi_command) = 0;
|
||||
|
||||
const string& GetType() const { return type; }
|
||||
|
||||
|
|
|
@ -74,9 +74,8 @@ DeviceFactory& DeviceFactory::instance()
|
|||
|
||||
void DeviceFactory::DeleteDevice(const PrimaryDevice *device) const
|
||||
{
|
||||
auto iterpair = devices.equal_range(device->GetId());
|
||||
|
||||
for (auto it = iterpair.first; it != iterpair.second; ++it) {
|
||||
auto [begin, end] = devices.equal_range(device->GetId());
|
||||
for (auto it = begin; it != end; ++it) {
|
||||
if (it->second->GetLun() == device->GetLun()) {
|
||||
devices.erase(it);
|
||||
|
||||
|
@ -219,7 +218,7 @@ PrimaryDevice *DeviceFactory::CreateDevice(PbDeviceType type, const string& file
|
|||
break;
|
||||
|
||||
case SCHS:
|
||||
device = make_unique<HostServices>();
|
||||
device = make_unique<HostServices>(this);
|
||||
// Since this is an emulation for a specific device the full INQUIRY data have to be set accordingly
|
||||
device->SetVendor("RaSCSI");
|
||||
device->SetProduct("Host Services");
|
||||
|
@ -264,9 +263,9 @@ list<string> DeviceFactory::GetNetworkInterfaces() const
|
|||
{
|
||||
list<string> network_interfaces;
|
||||
|
||||
struct ifaddrs *addrs;
|
||||
ifaddrs *addrs;
|
||||
getifaddrs(&addrs);
|
||||
struct ifaddrs *tmp = addrs;
|
||||
ifaddrs *tmp = addrs;
|
||||
|
||||
while (tmp) {
|
||||
if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_PACKET &&
|
||||
|
@ -276,7 +275,7 @@ list<string> DeviceFactory::GetNetworkInterfaces() const
|
|||
ifreq ifr = {};
|
||||
strcpy(ifr.ifr_name, tmp->ifa_name);
|
||||
// Only list interfaces that are up
|
||||
if (!ioctl(fd, SIOCGIFFLAGS, &ifr) && ifr.ifr_flags & IFF_UP) {
|
||||
if (!ioctl(fd, SIOCGIFFLAGS, &ifr) && (ifr.ifr_flags & IFF_UP)) {
|
||||
network_interfaces.emplace_back(tmp->ifa_name);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,34 +25,34 @@ using namespace scsi_defs;
|
|||
|
||||
Disk::Disk(const string& id) : ModePageDevice(id), ScsiBlockCommands()
|
||||
{
|
||||
dispatcher.AddCommand(eCmdRezero, "Rezero", &Disk::Rezero);
|
||||
dispatcher.AddCommand(eCmdFormat, "FormatUnit", &Disk::FormatUnit);
|
||||
dispatcher.AddCommand(eCmdReassign, "ReassignBlocks", &Disk::ReassignBlocks);
|
||||
dispatcher.AddCommand(eCmdRead6, "Read6", &Disk::Read6);
|
||||
dispatcher.AddCommand(eCmdWrite6, "Write6", &Disk::Write6);
|
||||
dispatcher.AddCommand(eCmdSeek6, "Seek6", &Disk::Seek6);
|
||||
dispatcher.AddCommand(eCmdReserve6, "Reserve6", &Disk::Reserve);
|
||||
dispatcher.AddCommand(eCmdRelease6, "Release6", &Disk::Release);
|
||||
dispatcher.AddCommand(eCmdStartStop, "StartStopUnit", &Disk::StartStopUnit);
|
||||
dispatcher.AddCommand(eCmdSendDiag, "SendDiagnostic", &Disk::SendDiagnostic);
|
||||
dispatcher.AddCommand(eCmdRemoval, "PreventAllowMediumRemoval", &Disk::PreventAllowMediumRemoval);
|
||||
dispatcher.AddCommand(eCmdReadCapacity10, "ReadCapacity10", &Disk::ReadCapacity10);
|
||||
dispatcher.AddCommand(eCmdRead10, "Read10", &Disk::Read10);
|
||||
dispatcher.AddCommand(eCmdWrite10, "Write10", &Disk::Write10);
|
||||
dispatcher.AddCommand(eCmdReadLong10, "ReadLong10", &Disk::ReadWriteLong10);
|
||||
dispatcher.AddCommand(eCmdWriteLong10, "WriteLong10", &Disk::ReadWriteLong10);
|
||||
dispatcher.AddCommand(eCmdWriteLong16, "WriteLong16", &Disk::ReadWriteLong16);
|
||||
dispatcher.AddCommand(eCmdSeek10, "Seek10", &Disk::Seek10);
|
||||
dispatcher.AddCommand(eCmdVerify10, "Verify10", &Disk::Verify10);
|
||||
dispatcher.AddCommand(eCmdSynchronizeCache10, "SynchronizeCache10", &Disk::SynchronizeCache10);
|
||||
dispatcher.AddCommand(eCmdSynchronizeCache16, "SynchronizeCache16", &Disk::SynchronizeCache16);
|
||||
dispatcher.AddCommand(eCmdReadDefectData10, "ReadDefectData10", &Disk::ReadDefectData10);
|
||||
dispatcher.AddCommand(eCmdReserve10, "Reserve10", &Disk::Reserve);
|
||||
dispatcher.AddCommand(eCmdRelease10, "Release10", &Disk::Release);
|
||||
dispatcher.AddCommand(eCmdRead16, "Read16", &Disk::Read16);
|
||||
dispatcher.AddCommand(eCmdWrite16, "Write16", &Disk::Write16);
|
||||
dispatcher.AddCommand(eCmdVerify16, "Verify16", &Disk::Verify16);
|
||||
dispatcher.AddCommand(eCmdReadCapacity16_ReadLong16, "ReadCapacity16/ReadLong16", &Disk::ReadCapacity16_ReadLong16);
|
||||
dispatcher.Add(scsi_command::eCmdRezero, "Rezero", &Disk::Rezero);
|
||||
dispatcher.Add(scsi_command::eCmdFormat, "FormatUnit", &Disk::FormatUnit);
|
||||
dispatcher.Add(scsi_command::eCmdReassign, "ReassignBlocks", &Disk::ReassignBlocks);
|
||||
dispatcher.Add(scsi_command::eCmdRead6, "Read6", &Disk::Read6);
|
||||
dispatcher.Add(scsi_command::eCmdWrite6, "Write6", &Disk::Write6);
|
||||
dispatcher.Add(scsi_command::eCmdSeek6, "Seek6", &Disk::Seek6);
|
||||
dispatcher.Add(scsi_command::eCmdReserve6, "Reserve6", &Disk::Reserve);
|
||||
dispatcher.Add(scsi_command::eCmdRelease6, "Release6", &Disk::Release);
|
||||
dispatcher.Add(scsi_command::eCmdStartStop, "StartStopUnit", &Disk::StartStopUnit);
|
||||
dispatcher.Add(scsi_command::eCmdSendDiag, "SendDiagnostic", &Disk::SendDiagnostic);
|
||||
dispatcher.Add(scsi_command::eCmdRemoval, "PreventAllowMediumRemoval", &Disk::PreventAllowMediumRemoval);
|
||||
dispatcher.Add(scsi_command::eCmdReadCapacity10, "ReadCapacity10", &Disk::ReadCapacity10);
|
||||
dispatcher.Add(scsi_command::eCmdRead10, "Read10", &Disk::Read10);
|
||||
dispatcher.Add(scsi_command::eCmdWrite10, "Write10", &Disk::Write10);
|
||||
dispatcher.Add(scsi_command::eCmdReadLong10, "ReadLong10", &Disk::ReadWriteLong10);
|
||||
dispatcher.Add(scsi_command::eCmdWriteLong10, "WriteLong10", &Disk::ReadWriteLong10);
|
||||
dispatcher.Add(scsi_command::eCmdWriteLong16, "WriteLong16", &Disk::ReadWriteLong16);
|
||||
dispatcher.Add(scsi_command::eCmdSeek10, "Seek10", &Disk::Seek10);
|
||||
dispatcher.Add(scsi_command::eCmdVerify10, "Verify10", &Disk::Verify10);
|
||||
dispatcher.Add(scsi_command::eCmdSynchronizeCache10, "SynchronizeCache10", &Disk::SynchronizeCache10);
|
||||
dispatcher.Add(scsi_command::eCmdSynchronizeCache16, "SynchronizeCache16", &Disk::SynchronizeCache16);
|
||||
dispatcher.Add(scsi_command::eCmdReadDefectData10, "ReadDefectData10", &Disk::ReadDefectData10);
|
||||
dispatcher.Add(scsi_command::eCmdReserve10, "Reserve10", &Disk::Reserve);
|
||||
dispatcher.Add(scsi_command::eCmdRelease10, "Release10", &Disk::Release);
|
||||
dispatcher.Add(scsi_command::eCmdRead16, "Read16", &Disk::Read16);
|
||||
dispatcher.Add(scsi_command::eCmdWrite16, "Write16", &Disk::Write16);
|
||||
dispatcher.Add(scsi_command::eCmdVerify16, "Verify16", &Disk::Verify16);
|
||||
dispatcher.Add(scsi_command::eCmdReadCapacity16_ReadLong16, "ReadCapacity16/ReadLong16", &Disk::ReadCapacity16_ReadLong16);
|
||||
}
|
||||
|
||||
Disk::~Disk()
|
||||
|
@ -65,7 +65,7 @@ Disk::~Disk()
|
|||
delete disk.dcache;
|
||||
}
|
||||
|
||||
bool Disk::Dispatch()
|
||||
bool Disk::Dispatch(scsi_command cmd)
|
||||
{
|
||||
// Media changes must be reported on the next access, i.e. not only for TEST UNIT READY
|
||||
if (disk.is_medium_changed) {
|
||||
|
@ -77,7 +77,7 @@ bool Disk::Dispatch()
|
|||
}
|
||||
|
||||
// The superclass handles the less specific commands
|
||||
return dispatcher.Dispatch(this, ctrl->cmd[0]) ? true : super::Dispatch();
|
||||
return dispatcher.Dispatch(this, cmd) ? true : super::Dispatch(cmd);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -94,10 +94,10 @@ void Disk::Open(const Filepath& path)
|
|||
|
||||
// Cache initialization
|
||||
assert (!disk.dcache);
|
||||
disk.dcache = new DiskCache(path, disk.size, disk.blocks, disk.image_offset);
|
||||
disk.dcache = new DiskCache(path, disk.size, (uint32_t)disk.blocks, disk.image_offset);
|
||||
|
||||
// Can read/write open
|
||||
if (Fileio fio; fio.Open(path, Fileio::ReadWrite)) {
|
||||
if (Fileio fio; fio.Open(path, Fileio::OpenMode::ReadWrite)) {
|
||||
// Write permission
|
||||
fio.Close();
|
||||
} else {
|
||||
|
@ -141,7 +141,7 @@ void Disk::Read(access_mode mode)
|
|||
uint64_t start;
|
||||
if (CheckAndGetStartAndCount(start, ctrl->blocks, mode)) {
|
||||
ctrl->length = Read(ctrl->cmd, ctrl->buffer, start);
|
||||
LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, (int)ctrl->length)
|
||||
LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, ctrl->length)
|
||||
|
||||
// Set next block
|
||||
ctrl->next = start + 1;
|
||||
|
@ -332,10 +332,10 @@ bool Disk::Eject(bool force)
|
|||
return status;
|
||||
}
|
||||
|
||||
int Disk::ModeSense6(const DWORD *cdb, BYTE *buf, int max_length)
|
||||
int Disk::ModeSense6(const vector<int>& cdb, BYTE *buf, int max_length) const
|
||||
{
|
||||
// Get length, clear buffer
|
||||
auto length = (int)cdb[4];
|
||||
auto length = cdb[4];
|
||||
if (length > max_length) {
|
||||
length = max_length;
|
||||
}
|
||||
|
@ -385,7 +385,7 @@ int Disk::ModeSense6(const DWORD *cdb, BYTE *buf, int max_length)
|
|||
return size;
|
||||
}
|
||||
|
||||
int Disk::ModeSense10(const DWORD *cdb, BYTE *buf, int max_length)
|
||||
int Disk::ModeSense10(const vector<int>& cdb, BYTE *buf, int max_length) const
|
||||
{
|
||||
// Get length, clear buffer
|
||||
int length = (cdb[7] << 8) | cdb[8];
|
||||
|
@ -397,56 +397,53 @@ int Disk::ModeSense10(const DWORD *cdb, BYTE *buf, int max_length)
|
|||
// Basic Information
|
||||
int size = 8;
|
||||
|
||||
// Add block descriptor if DBD is 0
|
||||
if ((cdb[1] & 0x08) == 0) {
|
||||
// Only if ready
|
||||
if (IsReady()) {
|
||||
uint64_t disk_blocks = GetBlockCount();
|
||||
uint32_t disk_size = GetSectorSizeInBytes();
|
||||
// Add block descriptor if DBD is 0, only if ready
|
||||
if ((cdb[1] & 0x08) == 0 && IsReady()) {
|
||||
uint64_t disk_blocks = GetBlockCount();
|
||||
uint32_t disk_size = GetSectorSizeInBytes();
|
||||
|
||||
// Check LLBAA for short or long block descriptor
|
||||
if ((cdb[1] & 0x10) == 0 || disk_blocks <= 0xFFFFFFFF) {
|
||||
// Mode parameter header, block descriptor length
|
||||
buf[7] = 0x08;
|
||||
// Check LLBAA for short or long block descriptor
|
||||
if ((cdb[1] & 0x10) == 0 || disk_blocks <= 0xFFFFFFFF) {
|
||||
// Mode parameter header, block descriptor length
|
||||
buf[7] = 0x08;
|
||||
|
||||
// Short LBA mode parameter block descriptor (number of blocks and block length)
|
||||
// Short LBA mode parameter block descriptor (number of blocks and block length)
|
||||
|
||||
buf[8] = (BYTE)(disk_blocks >> 24);
|
||||
buf[9] = (BYTE)(disk_blocks >> 16);
|
||||
buf[10] = (BYTE)(disk_blocks >> 8);
|
||||
buf[11] = (BYTE)disk_blocks;
|
||||
buf[8] = (BYTE)(disk_blocks >> 24);
|
||||
buf[9] = (BYTE)(disk_blocks >> 16);
|
||||
buf[10] = (BYTE)(disk_blocks >> 8);
|
||||
buf[11] = (BYTE)disk_blocks;
|
||||
|
||||
buf[13] = (BYTE)(disk_size >> 16);
|
||||
buf[14] = (BYTE)(disk_size >> 8);
|
||||
buf[15] = (BYTE)disk_size;
|
||||
buf[13] = (BYTE)(disk_size >> 16);
|
||||
buf[14] = (BYTE)(disk_size >> 8);
|
||||
buf[15] = (BYTE)disk_size;
|
||||
|
||||
size = 16;
|
||||
}
|
||||
else {
|
||||
// Mode parameter header, LONGLBA
|
||||
buf[4] = 0x01;
|
||||
size = 16;
|
||||
}
|
||||
else {
|
||||
// Mode parameter header, LONGLBA
|
||||
buf[4] = 0x01;
|
||||
|
||||
// Mode parameter header, block descriptor length
|
||||
buf[7] = 0x10;
|
||||
// Mode parameter header, block descriptor length
|
||||
buf[7] = 0x10;
|
||||
|
||||
// Long LBA mode parameter block descriptor (number of blocks and block length)
|
||||
// Long LBA mode parameter block descriptor (number of blocks and block length)
|
||||
|
||||
buf[8] = (BYTE)(disk_blocks >> 56);
|
||||
buf[9] = (BYTE)(disk_blocks >> 48);
|
||||
buf[10] = (BYTE)(disk_blocks >> 40);
|
||||
buf[11] = (BYTE)(disk_blocks >> 32);
|
||||
buf[12] = (BYTE)(disk_blocks >> 24);
|
||||
buf[13] = (BYTE)(disk_blocks >> 16);
|
||||
buf[14] = (BYTE)(disk_blocks >> 8);
|
||||
buf[15] = (BYTE)disk_blocks;
|
||||
buf[8] = (BYTE)(disk_blocks >> 56);
|
||||
buf[9] = (BYTE)(disk_blocks >> 48);
|
||||
buf[10] = (BYTE)(disk_blocks >> 40);
|
||||
buf[11] = (BYTE)(disk_blocks >> 32);
|
||||
buf[12] = (BYTE)(disk_blocks >> 24);
|
||||
buf[13] = (BYTE)(disk_blocks >> 16);
|
||||
buf[14] = (BYTE)(disk_blocks >> 8);
|
||||
buf[15] = (BYTE)disk_blocks;
|
||||
|
||||
buf[20] = (BYTE)(disk_size >> 24);
|
||||
buf[21] = (BYTE)(disk_size >> 16);
|
||||
buf[22] = (BYTE)(disk_size >> 8);
|
||||
buf[23] = (BYTE)disk_size;
|
||||
buf[20] = (BYTE)(disk_size >> 24);
|
||||
buf[21] = (BYTE)(disk_size >> 16);
|
||||
buf[22] = (BYTE)(disk_size >> 8);
|
||||
buf[23] = (BYTE)disk_size;
|
||||
|
||||
size = 24;
|
||||
}
|
||||
size = 24;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -475,7 +472,7 @@ void Disk::SetDeviceParameters(BYTE *buf) const
|
|||
}
|
||||
}
|
||||
|
||||
void Disk::AddModePages(map<int, vector<BYTE>>& pages, int page, bool changeable) const
|
||||
void Disk::AddModePages(map<int, vector<byte>>& pages, int page, bool changeable) const
|
||||
{
|
||||
// Page code 1 (read-write error recovery)
|
||||
if (page == 0x01 || page == 0x3f) {
|
||||
|
@ -501,18 +498,18 @@ void Disk::AddModePages(map<int, vector<BYTE>>& pages, int page, bool changeable
|
|||
AddVendorPage(pages, page, changeable);
|
||||
}
|
||||
|
||||
void Disk::AddErrorPage(map<int, vector<BYTE>>& pages, bool) const
|
||||
void Disk::AddErrorPage(map<int, vector<byte>>& pages, bool) const
|
||||
{
|
||||
vector<BYTE> buf(12);
|
||||
vector<byte> buf(12);
|
||||
|
||||
// Retry count is 0, limit time uses internal default value
|
||||
|
||||
pages[1] = buf;
|
||||
}
|
||||
|
||||
void Disk::AddFormatPage(map<int, vector<BYTE>>& pages, bool changeable) const
|
||||
void Disk::AddFormatPage(map<int, vector<byte>>& pages, bool changeable) const
|
||||
{
|
||||
vector<BYTE> buf(24);
|
||||
vector<byte> buf(24);
|
||||
|
||||
// No changeable area
|
||||
if (changeable) {
|
||||
|
@ -523,41 +520,41 @@ void Disk::AddFormatPage(map<int, vector<BYTE>>& pages, bool changeable) const
|
|||
|
||||
if (IsReady()) {
|
||||
// Set the number of tracks in one zone to 8
|
||||
buf[0x03] = 0x08;
|
||||
buf[0x03] = (byte)0x08;
|
||||
|
||||
// Set sector/track to 25
|
||||
buf[0x0a] = 0x00;
|
||||
buf[0x0b] = 0x19;
|
||||
buf[0x0a] = (byte)0x00;
|
||||
buf[0x0b] = (byte)0x19;
|
||||
|
||||
// Set the number of bytes in the physical sector
|
||||
int size = 1 << disk.size;
|
||||
buf[0x0c] = (BYTE)(size >> 8);
|
||||
buf[0x0d] = (BYTE)size;
|
||||
buf[0x0c] = (byte)(size >> 8);
|
||||
buf[0x0d] = (byte)size;
|
||||
|
||||
// Interleave 1
|
||||
buf[0x0e] = 0x00;
|
||||
buf[0x0f] = 0x01;
|
||||
buf[0x0e] = (byte)0x00;
|
||||
buf[0x0f] = (byte)0x01;
|
||||
|
||||
// Track skew factor 11
|
||||
buf[0x10] = 0x00;
|
||||
buf[0x11] = 0x0b;
|
||||
buf[0x10] = (byte)0x00;
|
||||
buf[0x11] = (byte)0x0b;
|
||||
|
||||
// Cylinder skew factor 20
|
||||
buf[0x12] = 0x00;
|
||||
buf[0x13] = 0x14;
|
||||
buf[0x12] = (byte)0x00;
|
||||
buf[0x13] = (byte)0x14;
|
||||
}
|
||||
|
||||
buf[20] = IsRemovable() ? 0x20 : 0x00;
|
||||
buf[20] = IsRemovable() ? (byte)0x20 : (byte)0x00;
|
||||
|
||||
// Hard-sectored
|
||||
buf[20] |= 0x40;
|
||||
buf[20] |= (byte)0x40;
|
||||
|
||||
pages[3] = buf;
|
||||
}
|
||||
|
||||
void Disk::AddDrivePage(map<int, vector<BYTE>>& pages, bool changeable) const
|
||||
void Disk::AddDrivePage(map<int, vector<byte>>& pages, bool changeable) const
|
||||
{
|
||||
vector<BYTE> buf(24);
|
||||
vector<byte> buf(24);
|
||||
|
||||
// No changeable area
|
||||
if (changeable) {
|
||||
|
@ -572,24 +569,24 @@ void Disk::AddDrivePage(map<int, vector<BYTE>>& pages, bool changeable) const
|
|||
uint64_t cylinders = disk.blocks;
|
||||
cylinders >>= 3;
|
||||
cylinders /= 25;
|
||||
buf[0x02] = (BYTE)(cylinders >> 16);
|
||||
buf[0x03] = (BYTE)(cylinders >> 8);
|
||||
buf[0x04] = (BYTE)cylinders;
|
||||
buf[0x02] = (byte)(cylinders >> 16);
|
||||
buf[0x03] = (byte)(cylinders >> 8);
|
||||
buf[0x04] = (byte)cylinders;
|
||||
|
||||
// Fix the head at 8
|
||||
buf[0x05] = 0x8;
|
||||
buf[0x05] = (byte)0x8;
|
||||
|
||||
// Medium rotation rate 7200
|
||||
buf[0x14] = 0x1c;
|
||||
buf[0x15] = 0x20;
|
||||
buf[0x14] = (byte)0x1c;
|
||||
buf[0x15] = (byte)0x20;
|
||||
}
|
||||
|
||||
pages[4] = buf;
|
||||
}
|
||||
|
||||
void Disk::AddCachePage(map<int, vector<BYTE>>& pages, bool changeable) const
|
||||
void Disk::AddCachePage(map<int, vector<byte>>& pages, bool changeable) const
|
||||
{
|
||||
vector<BYTE> buf(12);
|
||||
vector<byte> buf(12);
|
||||
|
||||
// No changeable area
|
||||
if (changeable) {
|
||||
|
@ -601,26 +598,26 @@ void Disk::AddCachePage(map<int, vector<BYTE>>& pages, bool changeable) const
|
|||
// Only read cache is valid
|
||||
|
||||
// Disable pre-fetch transfer length
|
||||
buf[0x04] = 0xff;
|
||||
buf[0x05] = 0xff;
|
||||
buf[0x04] = (byte)0xff;
|
||||
buf[0x05] = (byte)0xff;
|
||||
|
||||
// Maximum pre-fetch
|
||||
buf[0x08] = 0xff;
|
||||
buf[0x09] = 0xff;
|
||||
buf[0x08] = (byte)0xff;
|
||||
buf[0x09] = (byte)0xff;
|
||||
|
||||
// Maximum pre-fetch ceiling
|
||||
buf[0x0a] = 0xff;
|
||||
buf[0x0b] = 0xff;
|
||||
buf[0x0a] = (byte)0xff;
|
||||
buf[0x0b] = (byte)0xff;
|
||||
|
||||
pages[8] = buf;
|
||||
}
|
||||
|
||||
void Disk::AddVendorPage(map<int, vector<BYTE>>&, int, bool) const
|
||||
void Disk::AddVendorPage(map<int, vector<byte>>&, int, bool) const
|
||||
{
|
||||
// Nothing to add by default
|
||||
}
|
||||
|
||||
void Disk::Format(const DWORD *cdb)
|
||||
void Disk::Format(const vector<int>& cdb)
|
||||
{
|
||||
CheckReady();
|
||||
|
||||
|
@ -631,7 +628,7 @@ void Disk::Format(const DWORD *cdb)
|
|||
}
|
||||
|
||||
// TODO Read more than one block in a single call. Currently blocked by the the track-oriented cache
|
||||
int Disk::Read(const DWORD *, BYTE *buf, uint64_t block)
|
||||
int Disk::Read(const vector<int>&, BYTE *buf, uint64_t block)
|
||||
{
|
||||
LOGTRACE("%s", __PRETTY_FUNCTION__)
|
||||
|
||||
|
@ -643,7 +640,7 @@ int Disk::Read(const DWORD *, BYTE *buf, uint64_t block)
|
|||
}
|
||||
|
||||
// leave it to the cache
|
||||
if (!disk.dcache->ReadSector(buf, block)) {
|
||||
if (!disk.dcache->ReadSector(buf, (uint32_t)block)) {
|
||||
throw scsi_error_exception(sense_key::MEDIUM_ERROR, asc::READ_FAULT);
|
||||
}
|
||||
|
||||
|
@ -670,7 +667,7 @@ int Disk::WriteCheck(uint64_t block)
|
|||
}
|
||||
|
||||
// TODO Write more than one block in a single call. Currently blocked by the track-oriented cache
|
||||
void Disk::Write(const DWORD *, BYTE *buf, uint64_t block)
|
||||
void Disk::Write(const vector<int>&, const BYTE *buf, uint64_t block)
|
||||
{
|
||||
LOGTRACE("%s", __PRETTY_FUNCTION__)
|
||||
|
||||
|
@ -690,7 +687,7 @@ void Disk::Write(const DWORD *, BYTE *buf, uint64_t block)
|
|||
}
|
||||
|
||||
// Leave it to the cache
|
||||
if (!disk.dcache->WriteSector(buf, block)) {
|
||||
if (!disk.dcache->WriteSector(buf, (uint32_t)block)) {
|
||||
throw scsi_error_exception(sense_key::MEDIUM_ERROR, asc::WRITE_FAULT);
|
||||
}
|
||||
}
|
||||
|
@ -718,7 +715,7 @@ void Disk::Seek10()
|
|||
}
|
||||
}
|
||||
|
||||
bool Disk::StartStop(const DWORD *cdb)
|
||||
bool Disk::StartStop(const vector<int>& cdb)
|
||||
{
|
||||
bool start = cdb[4] & 0x01;
|
||||
bool load = cdb[4] & 0x02;
|
||||
|
@ -750,7 +747,7 @@ bool Disk::StartStop(const DWORD *cdb)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Disk::SendDiag(const DWORD *cdb) const
|
||||
bool Disk::SendDiag(const vector<int>& cdb) const
|
||||
{
|
||||
// Do not support PF bit
|
||||
if (cdb[1] & 0x10) {
|
||||
|
@ -776,7 +773,12 @@ void Disk::ReadCapacity10()
|
|||
BYTE *buf = ctrl->buffer;
|
||||
|
||||
// Create end of logical block address (disk.blocks-1)
|
||||
uint32_t blocks = disk.blocks - 1;
|
||||
uint64_t blocks = disk.blocks - 1;
|
||||
|
||||
// If the capacity exceeds 32 bit, -1 must be returned and the client has to use READ CAPACITY(16)
|
||||
if (blocks > 4294967295) {
|
||||
blocks = -1;
|
||||
}
|
||||
buf[0] = (BYTE)(blocks >> 24);
|
||||
buf[1] = (BYTE)(blocks >> 16);
|
||||
buf[2] = (BYTE)(blocks >> 8);
|
||||
|
|
|
@ -59,16 +59,16 @@ public:
|
|||
Disk(Disk&) = delete;
|
||||
Disk& operator=(const Disk&) = delete;
|
||||
|
||||
bool Dispatch() override;
|
||||
bool Dispatch(scsi_command) override;
|
||||
|
||||
void MediumChanged();
|
||||
bool Eject(bool) override;
|
||||
|
||||
// Command helpers
|
||||
virtual int WriteCheck(uint64_t);
|
||||
virtual void Write(const DWORD *, BYTE *, uint64_t);
|
||||
virtual void Write(const vector<int>&, const BYTE *, uint64_t);
|
||||
|
||||
virtual int Read(const DWORD *, BYTE *, uint64_t);
|
||||
virtual int Read(const vector<int>&, BYTE *, uint64_t);
|
||||
|
||||
uint32_t GetSectorSizeInBytes() const;
|
||||
bool IsSectorSizeConfigurable() const;
|
||||
|
@ -111,27 +111,27 @@ private:
|
|||
void ReadWriteLong10();
|
||||
void ReadWriteLong16();
|
||||
void ReadCapacity16_ReadLong16();
|
||||
void Format(const DWORD *);
|
||||
bool SendDiag(const DWORD *) const;
|
||||
bool StartStop(const DWORD *);
|
||||
void Format(const vector<int>&);
|
||||
bool SendDiag(const vector<int>&) const;
|
||||
bool StartStop(const vector<int>&);
|
||||
|
||||
void ValidateBlockAddress(access_mode) const;
|
||||
bool CheckAndGetStartAndCount(uint64_t&, uint32_t&, access_mode);
|
||||
|
||||
int ModeSense6(const DWORD *, BYTE *, int) override;
|
||||
int ModeSense10(const DWORD *, BYTE *, int) override;
|
||||
int ModeSense6(const vector<int>&, BYTE *, int) const override;
|
||||
int ModeSense10(const vector<int>&, BYTE *, int) const override;
|
||||
|
||||
protected:
|
||||
|
||||
virtual void Open(const Filepath&);
|
||||
|
||||
virtual void SetDeviceParameters(BYTE *) const;
|
||||
void AddModePages(map<int, vector<BYTE>>&, int, bool) const override;
|
||||
virtual void AddErrorPage(map<int, vector<BYTE>>&, bool) const;
|
||||
virtual void AddFormatPage(map<int, vector<BYTE>>&, bool) const;
|
||||
virtual void AddDrivePage(map<int, vector<BYTE>>&, bool) const;
|
||||
void AddCachePage(map<int, vector<BYTE>>&, bool) const;
|
||||
virtual void AddVendorPage(map<int, vector<BYTE>>&, int, bool) const;
|
||||
void AddModePages(map<int, vector<byte>>&, int, bool) const override;
|
||||
virtual void AddErrorPage(map<int, vector<byte>>&, bool) const;
|
||||
virtual void AddFormatPage(map<int, vector<byte>>&, bool) const;
|
||||
virtual void AddDrivePage(map<int, vector<byte>>&, bool) const;
|
||||
void AddCachePage(map<int, vector<byte>>&, bool) const;
|
||||
virtual void AddVendorPage(map<int, vector<byte>>&, int, bool) const;
|
||||
unordered_set<uint32_t> GetSectorSizes() const;
|
||||
void SetSectorSizes(const unordered_set<uint32_t>&);
|
||||
void SetSectorSizeInBytes(uint32_t);
|
||||
|
|
|
@ -38,11 +38,11 @@ DiskTrack::~DiskTrack()
|
|||
}
|
||||
}
|
||||
|
||||
void DiskTrack::Init(int track, int size, int sectors, BOOL raw, off_t imgoff)
|
||||
void DiskTrack::Init(int track, int size, int sectors, bool raw, off_t imgoff)
|
||||
{
|
||||
ASSERT(track >= 0);
|
||||
ASSERT((sectors > 0) && (sectors <= 0x100));
|
||||
ASSERT(imgoff >= 0);
|
||||
assert(track >= 0);
|
||||
assert((sectors > 0) && (sectors <= 0x100));
|
||||
assert(imgoff >= 0);
|
||||
|
||||
// Set Parameters
|
||||
dt.track = track;
|
||||
|
@ -51,10 +51,10 @@ void DiskTrack::Init(int track, int size, int sectors, BOOL raw, off_t imgoff)
|
|||
dt.raw = raw;
|
||||
|
||||
// Not initialized (needs to be loaded)
|
||||
dt.init = FALSE;
|
||||
dt.init = false;
|
||||
|
||||
// Not Changed
|
||||
dt.changed = FALSE;
|
||||
dt.changed = false;
|
||||
|
||||
// Offset to actual data
|
||||
dt.imgoffset = imgoff;
|
||||
|
@ -64,15 +64,15 @@ bool DiskTrack::Load(const Filepath& path)
|
|||
{
|
||||
// Not needed if already loaded
|
||||
if (dt.init) {
|
||||
ASSERT(dt.buffer);
|
||||
ASSERT(dt.changemap);
|
||||
assert(dt.buffer);
|
||||
assert(dt.changemap);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Calculate offset (previous tracks are considered to hold 256 sectors)
|
||||
off_t offset = ((off_t)dt.track << 8);
|
||||
if (dt.raw) {
|
||||
ASSERT(dt.size == 11);
|
||||
assert(dt.size == 11);
|
||||
offset *= 0x930;
|
||||
offset += 0x10;
|
||||
} else {
|
||||
|
@ -86,12 +86,12 @@ bool DiskTrack::Load(const Filepath& path)
|
|||
int length = dt.sectors << dt.size;
|
||||
|
||||
// Allocate buffer memory
|
||||
ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100));
|
||||
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
|
||||
|
||||
if (dt.buffer == nullptr) {
|
||||
if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) {
|
||||
LOGWARN("%s posix_memalign failed", __PRETTY_FUNCTION__)
|
||||
}
|
||||
if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) {
|
||||
LOGWARN("%s posix_memalign failed", __PRETTY_FUNCTION__)
|
||||
}
|
||||
dt.length = length;
|
||||
}
|
||||
|
||||
|
@ -103,14 +103,14 @@ bool DiskTrack::Load(const Filepath& path)
|
|||
if (dt.length != (DWORD)length) {
|
||||
free(dt.buffer);
|
||||
if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) {
|
||||
LOGWARN("%s posix_memalign failed", __PRETTY_FUNCTION__)
|
||||
}
|
||||
LOGWARN("%s posix_memalign failed", __PRETTY_FUNCTION__)
|
||||
}
|
||||
dt.length = length;
|
||||
}
|
||||
|
||||
// Reserve change map memory
|
||||
if (dt.changemap == nullptr) {
|
||||
dt.changemap = (BOOL *)malloc(dt.sectors * sizeof(BOOL));
|
||||
dt.changemap = (bool *)malloc(dt.sectors * sizeof(bool));
|
||||
dt.maplen = dt.sectors;
|
||||
}
|
||||
|
||||
|
@ -121,16 +121,16 @@ bool DiskTrack::Load(const Filepath& path)
|
|||
// Reallocate if the buffer length is different
|
||||
if (dt.maplen != (DWORD)dt.sectors) {
|
||||
free(dt.changemap);
|
||||
dt.changemap = (BOOL *)malloc(dt.sectors * sizeof(BOOL));
|
||||
dt.changemap = (bool *)malloc(dt.sectors * sizeof(bool));
|
||||
dt.maplen = dt.sectors;
|
||||
}
|
||||
|
||||
// Clear changemap
|
||||
memset(dt.changemap, 0x00, dt.sectors * sizeof(BOOL));
|
||||
memset(dt.changemap, 0x00, dt.sectors * sizeof(bool));
|
||||
|
||||
// Read from File
|
||||
Fileio fio;
|
||||
if (!fio.OpenDIO(path, Fileio::ReadOnly)) {
|
||||
if (!fio.OpenDIO(path, Fileio::OpenMode::ReadOnly)) {
|
||||
return false;
|
||||
}
|
||||
if (dt.raw) {
|
||||
|
@ -165,8 +165,8 @@ bool DiskTrack::Load(const Filepath& path)
|
|||
fio.Close();
|
||||
|
||||
// Set a flag and end normally
|
||||
dt.init = TRUE;
|
||||
dt.changed = FALSE;
|
||||
dt.init = true;
|
||||
dt.changed = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -183,12 +183,12 @@ bool DiskTrack::Save(const Filepath& path)
|
|||
}
|
||||
|
||||
// Need to write
|
||||
ASSERT(dt.buffer);
|
||||
ASSERT(dt.changemap);
|
||||
ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100));
|
||||
assert(dt.buffer);
|
||||
assert(dt.changemap);
|
||||
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
|
||||
|
||||
// Writing in RAW mode is not allowed
|
||||
ASSERT(!dt.raw);
|
||||
assert(!dt.raw);
|
||||
|
||||
// Calculate offset (previous tracks are considered to hold 256 sectors)
|
||||
off_t offset = ((off_t)dt.track << 8);
|
||||
|
@ -202,7 +202,7 @@ bool DiskTrack::Save(const Filepath& path)
|
|||
|
||||
// Open file
|
||||
Fileio fio;
|
||||
if (!fio.Open(path, Fileio::ReadWrite)) {
|
||||
if (!fio.Open(path, Fileio::OpenMode::ReadWrite)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -250,15 +250,14 @@ bool DiskTrack::Save(const Filepath& path)
|
|||
fio.Close();
|
||||
|
||||
// Drop the change flag and exit
|
||||
memset(dt.changemap, 0x00, dt.sectors * sizeof(BOOL));
|
||||
dt.changed = FALSE;
|
||||
memset(dt.changemap, 0x00, dt.sectors * sizeof(bool));
|
||||
dt.changed = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiskTrack::ReadSector(BYTE *buf, int sec) const
|
||||
{
|
||||
ASSERT(buf);
|
||||
ASSERT((sec >= 0) && (sec < 0x100));
|
||||
assert((sec >= 0) && (sec < 0x100));
|
||||
|
||||
LOGTRACE("%s reading sector: %d", __PRETTY_FUNCTION__,sec)
|
||||
// Error if not initialized
|
||||
|
@ -272,8 +271,8 @@ bool DiskTrack::ReadSector(BYTE *buf, int sec) const
|
|||
}
|
||||
|
||||
// Copy
|
||||
ASSERT(dt.buffer);
|
||||
ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100));
|
||||
assert(dt.buffer);
|
||||
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
|
||||
memcpy(buf, &dt.buffer[(off_t)sec << dt.size], (off_t)1 << dt.size);
|
||||
|
||||
// Success
|
||||
|
@ -282,9 +281,8 @@ bool DiskTrack::ReadSector(BYTE *buf, int sec) const
|
|||
|
||||
bool DiskTrack::WriteSector(const BYTE *buf, int sec)
|
||||
{
|
||||
ASSERT(buf);
|
||||
ASSERT((sec >= 0) && (sec < 0x100));
|
||||
ASSERT(!dt.raw);
|
||||
assert((sec >= 0) && (sec < 0x100));
|
||||
assert(!dt.raw);
|
||||
|
||||
// Error if not initialized
|
||||
if (!dt.init) {
|
||||
|
@ -301,8 +299,8 @@ bool DiskTrack::WriteSector(const BYTE *buf, int sec)
|
|||
int length = 1 << dt.size;
|
||||
|
||||
// Compare
|
||||
ASSERT(dt.buffer);
|
||||
ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100));
|
||||
assert(dt.buffer);
|
||||
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
|
||||
if (memcmp(buf, &dt.buffer[offset], length) == 0) {
|
||||
// Exit normally since it's attempting to write the same thing
|
||||
return true;
|
||||
|
@ -310,8 +308,8 @@ bool DiskTrack::WriteSector(const BYTE *buf, int sec)
|
|||
|
||||
// Copy, change
|
||||
memcpy(&dt.buffer[offset], buf, length);
|
||||
dt.changemap[sec] = TRUE;
|
||||
dt.changed = TRUE;
|
||||
dt.changemap[sec] = true;
|
||||
dt.changed = true;
|
||||
|
||||
// Success
|
||||
return true;
|
||||
|
@ -324,23 +322,12 @@ bool DiskTrack::WriteSector(const BYTE *buf, int sec)
|
|||
//===========================================================================
|
||||
|
||||
DiskCache::DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgoff)
|
||||
: sec_size(size), sec_blocks(blocks), imgoffset(imgoff)
|
||||
{
|
||||
ASSERT(blocks > 0);
|
||||
ASSERT(imgoff >= 0);
|
||||
assert(blocks > 0);
|
||||
assert(imgoff >= 0);
|
||||
|
||||
// Cache work
|
||||
for (int i = 0; i < CACHE_MAX; i++) {
|
||||
cache[i].disktrk = nullptr;
|
||||
cache[i].serial = 0;
|
||||
}
|
||||
|
||||
// Other
|
||||
serial = 0;
|
||||
sec_path = path;
|
||||
sec_size = size;
|
||||
sec_blocks = blocks;
|
||||
cd_raw = FALSE;
|
||||
imgoffset = imgoff;
|
||||
}
|
||||
|
||||
DiskCache::~DiskCache()
|
||||
|
@ -349,22 +336,19 @@ DiskCache::~DiskCache()
|
|||
Clear();
|
||||
}
|
||||
|
||||
void DiskCache::SetRawMode(BOOL raw)
|
||||
void DiskCache::SetRawMode(bool raw)
|
||||
{
|
||||
// Configuration
|
||||
cd_raw = raw;
|
||||
}
|
||||
|
||||
bool DiskCache::Save()
|
||||
bool DiskCache::Save() const
|
||||
{
|
||||
// Save track
|
||||
for (int i = 0; i < CACHE_MAX; i++) {
|
||||
// Is it a valid track?
|
||||
if (cache[i].disktrk) {
|
||||
// Save
|
||||
if (!cache[i].disktrk->Save(sec_path)) {
|
||||
return false;
|
||||
}
|
||||
for (cache_t c : cache) {
|
||||
// Save if this is a valid track
|
||||
if (c.disktrk && !c.disktrk->Save(sec_path)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,7 +362,7 @@ bool DiskCache::Save()
|
|||
//---------------------------------------------------------------------------
|
||||
bool DiskCache::GetCache(int index, int& track, DWORD& aserial) const
|
||||
{
|
||||
ASSERT((index >= 0) && (index < CACHE_MAX));
|
||||
assert((index >= 0) && (index < CACHE_MAX));
|
||||
|
||||
// false if unused
|
||||
if (!cache[index].disktrk) {
|
||||
|
@ -395,17 +379,17 @@ bool DiskCache::GetCache(int index, int& track, DWORD& aserial) const
|
|||
void DiskCache::Clear()
|
||||
{
|
||||
// Free the cache
|
||||
for (int i = 0; i < CACHE_MAX; i++) {
|
||||
if (cache[i].disktrk) {
|
||||
delete cache[i].disktrk;
|
||||
cache[i].disktrk = nullptr;
|
||||
for (cache_t& c : cache) {
|
||||
if (c.disktrk) {
|
||||
delete c.disktrk;
|
||||
c.disktrk = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DiskCache::ReadSector(BYTE *buf, int block)
|
||||
bool DiskCache::ReadSector(BYTE *buf, uint32_t block)
|
||||
{
|
||||
ASSERT(sec_size != 0);
|
||||
assert(sec_size != 0);
|
||||
|
||||
// Update first
|
||||
UpdateSerialNumber();
|
||||
|
@ -423,9 +407,9 @@ bool DiskCache::ReadSector(BYTE *buf, int block)
|
|||
return disktrk->ReadSector(buf, block & 0xff);
|
||||
}
|
||||
|
||||
bool DiskCache::WriteSector(const BYTE *buf, int block)
|
||||
bool DiskCache::WriteSector(const BYTE *buf, uint32_t block)
|
||||
{
|
||||
ASSERT(sec_size != 0);
|
||||
assert(sec_size != 0);
|
||||
|
||||
// Update first
|
||||
UpdateSerialNumber();
|
||||
|
@ -450,17 +434,15 @@ bool DiskCache::WriteSector(const BYTE *buf, int block)
|
|||
//---------------------------------------------------------------------------
|
||||
DiskTrack* DiskCache::Assign(int track)
|
||||
{
|
||||
ASSERT(sec_size != 0);
|
||||
ASSERT(track >= 0);
|
||||
assert(sec_size != 0);
|
||||
assert(track >= 0);
|
||||
|
||||
// First, check if it is already assigned
|
||||
for (int i = 0; i < CACHE_MAX; i++) {
|
||||
if (cache[i].disktrk) {
|
||||
if (cache[i].disktrk->GetTrack() == track) {
|
||||
// Track match
|
||||
cache[i].serial = serial;
|
||||
return cache[i].disktrk;
|
||||
}
|
||||
for (cache_t c : cache) {
|
||||
if (c.disktrk && c.disktrk->GetTrack() == track) {
|
||||
// Track match
|
||||
c.serial = serial;
|
||||
return c.disktrk;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -487,7 +469,7 @@ DiskTrack* DiskCache::Assign(int track)
|
|||
|
||||
// Compare candidate with serial and update to smaller one
|
||||
for (int i = 0; i < CACHE_MAX; i++) {
|
||||
ASSERT(cache[i].disktrk);
|
||||
assert(cache[i].disktrk);
|
||||
|
||||
// Compare and update the existing serial
|
||||
if (cache[i].serial < s) {
|
||||
|
@ -522,13 +504,13 @@ DiskTrack* DiskCache::Assign(int track)
|
|||
//---------------------------------------------------------------------------
|
||||
bool DiskCache::Load(int index, int track, DiskTrack *disktrk)
|
||||
{
|
||||
ASSERT((index >= 0) && (index < CACHE_MAX));
|
||||
ASSERT(track >= 0);
|
||||
ASSERT(!cache[index].disktrk);
|
||||
assert((index >= 0) && (index < CACHE_MAX));
|
||||
assert(track >= 0);
|
||||
assert(!cache[index].disktrk);
|
||||
|
||||
// Get the number of sectors on this track
|
||||
int sectors = sec_blocks - (track << 8);
|
||||
ASSERT(sectors > 0);
|
||||
assert(sectors > 0);
|
||||
if (sectors > 0x100) {
|
||||
sectors = 0x100;
|
||||
}
|
||||
|
@ -562,9 +544,9 @@ void DiskCache::UpdateSerialNumber()
|
|||
return;
|
||||
}
|
||||
|
||||
// Clear serial of all caches (loop in 32bit)
|
||||
for (int i = 0; i < CACHE_MAX; i++) {
|
||||
cache[i].serial = 0;
|
||||
// Clear serial of all caches
|
||||
for (cache_t& c : cache) {
|
||||
c.serial = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,18 +25,19 @@ static const int CACHE_MAX = 16;
|
|||
class DiskTrack
|
||||
{
|
||||
private:
|
||||
|
||||
struct {
|
||||
int track; // Track Number
|
||||
int size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096)
|
||||
int sectors; // Number of sectors(<0x100)
|
||||
DWORD length; // Data buffer length
|
||||
BYTE *buffer; // Data buffer
|
||||
BOOL init; // Is it initilized?
|
||||
BOOL changed; // Changed flag
|
||||
DWORD maplen; // Changed map length
|
||||
BOOL *changemap; // Changed map
|
||||
BOOL raw; // RAW mode flag
|
||||
off_t imgoffset; // Offset to actual data
|
||||
int sectors; // Number of sectors(<0x100)
|
||||
DWORD length; // Data buffer length
|
||||
BYTE *buffer; // Data buffer
|
||||
bool init; // Is it initilized?
|
||||
bool changed; // Changed flag
|
||||
DWORD maplen; // Changed map length
|
||||
bool *changemap; // Changed map
|
||||
bool raw; // RAW mode flag
|
||||
off_t imgoffset; // Offset to actual data
|
||||
} dt = {};
|
||||
|
||||
public:
|
||||
|
@ -48,7 +49,7 @@ public:
|
|||
private:
|
||||
friend class DiskCache;
|
||||
|
||||
void Init(int track, int size, int sectors, BOOL raw = FALSE, off_t imgoff = 0);
|
||||
void Init(int track, int size, int sectors, bool raw = false, off_t imgoff = 0);
|
||||
bool Load(const Filepath& path);
|
||||
bool Save(const Filepath& path);
|
||||
|
||||
|
@ -73,12 +74,12 @@ public:
|
|||
DiskCache(DiskCache&) = delete;
|
||||
DiskCache& operator=(const DiskCache&) = delete;
|
||||
|
||||
void SetRawMode(BOOL raw); // CD-ROM raw mode setting
|
||||
void SetRawMode(bool); // CD-ROM raw mode setting
|
||||
|
||||
// Access
|
||||
bool Save(); // Save and release all
|
||||
bool ReadSector(BYTE *buf, int block); // Sector Read
|
||||
bool WriteSector(const BYTE *buf, int block); // Sector Write
|
||||
bool Save() const; // Save and release all
|
||||
bool ReadSector(BYTE *buf, uint32_t block); // Sector Read
|
||||
bool WriteSector(const BYTE *buf, uint32_t block); // Sector Write
|
||||
bool GetCache(int index, int& track, DWORD& serial) const; // Get cache information
|
||||
|
||||
private:
|
||||
|
@ -89,12 +90,12 @@ private:
|
|||
void UpdateSerialNumber(); // Update serial number
|
||||
|
||||
// Internal data
|
||||
cache_t cache[CACHE_MAX]; // Cache management
|
||||
DWORD serial; // Last serial number
|
||||
cache_t cache[CACHE_MAX] = {}; // Cache management
|
||||
DWORD serial = 0; // Last serial number
|
||||
Filepath sec_path; // Path
|
||||
int sec_size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096)
|
||||
int sec_blocks; // Blocks per sector
|
||||
BOOL cd_raw; // CD-ROM RAW mode
|
||||
bool cd_raw = false; // CD-ROM RAW mode
|
||||
off_t imgoffset; // Offset to actual data
|
||||
};
|
||||
|
||||
|
|
|
@ -30,22 +30,22 @@ public:
|
|||
|
||||
using operation = void (T::*)();
|
||||
using command_t = struct _command_t {
|
||||
const char* name;
|
||||
const char *name;
|
||||
operation execute;
|
||||
|
||||
_command_t(const char* _name, operation _execute) : name(_name), execute(_execute) { };
|
||||
_command_t(const char *_name, operation _execute) : name(_name), execute(_execute) { };
|
||||
};
|
||||
unordered_map<scsi_command, unique_ptr<command_t>> commands;
|
||||
|
||||
void AddCommand(scsi_command opcode, const char* name, operation execute)
|
||||
void Add(scsi_command opcode, const char *name, operation execute)
|
||||
{
|
||||
commands[opcode] = make_unique<command_t>(name, execute);
|
||||
}
|
||||
|
||||
bool Dispatch(T *instance, DWORD cmd)
|
||||
bool Dispatch(T *instance, scsi_command cmd)
|
||||
{
|
||||
if (const auto& it = commands.find(static_cast<scsi_command>(cmd)); it != commands.end()) {
|
||||
LOGDEBUG("%s Executing %s ($%02X)", __PRETTY_FUNCTION__, it->second->name, (uint32_t)cmd)
|
||||
if (const auto& it = commands.find(cmd); it != commands.end()) {
|
||||
LOGDEBUG("%s Executing %s ($%02X)", __PRETTY_FUNCTION__, it->second->name, (int)cmd)
|
||||
|
||||
(instance->*it->second->execute)();
|
||||
|
||||
|
|
|
@ -12,20 +12,7 @@
|
|||
//
|
||||
// Features of the host services device:
|
||||
//
|
||||
// 1. Vendor-specific mode page 0x20 returns the current date and time (realtime clock)
|
||||
//
|
||||
// typedef struct {
|
||||
// // Major and minor version of this data structure
|
||||
// uint8_t major_version;
|
||||
// uint8_t minor_version;
|
||||
// // Current date and time, with daylight savings time adjustment applied
|
||||
// uint8_t year; // year - 1900
|
||||
// uint8_t month; // 0-11
|
||||
// uint8_t day; // 1-31
|
||||
// uint8_t hour; // 0-23
|
||||
// uint8_t minute; // 0-59
|
||||
// uint8_t second; // 0-59
|
||||
// } mode_page_datetime;
|
||||
// 1. Vendor-specific mode page 0x20 returns the current date and time, see mode_page_datetime
|
||||
//
|
||||
// 2. START/STOP UNIT shuts down RaSCSI or shuts down/reboots the Raspberry Pi
|
||||
// a) !start && !load (STOP): Shut down RaSCSI
|
||||
|
@ -40,16 +27,16 @@
|
|||
|
||||
using namespace scsi_defs;
|
||||
|
||||
HostServices::HostServices() : ModePageDevice("SCHS")
|
||||
HostServices::HostServices(const DeviceFactory *factory) : ModePageDevice("SCHS"), device_factory(factory)
|
||||
{
|
||||
dispatcher.AddCommand(eCmdTestUnitReady, "TestUnitReady", &HostServices::TestUnitReady);
|
||||
dispatcher.AddCommand(eCmdStartStop, "StartStopUnit", &HostServices::StartStopUnit);
|
||||
dispatcher.Add(scsi_command::eCmdTestUnitReady, "TestUnitReady", &HostServices::TestUnitReady);
|
||||
dispatcher.Add(scsi_command::eCmdStartStop, "StartStopUnit", &HostServices::StartStopUnit);
|
||||
}
|
||||
|
||||
bool HostServices::Dispatch()
|
||||
bool HostServices::Dispatch(scsi_command cmd)
|
||||
{
|
||||
// The superclass class handles the less specific commands
|
||||
return dispatcher.Dispatch(this, ctrl->cmd[0]) ? true : super::Dispatch();
|
||||
return dispatcher.Dispatch(this, cmd) ? true : super::Dispatch(cmd);
|
||||
}
|
||||
|
||||
void HostServices::TestUnitReady()
|
||||
|
@ -58,7 +45,7 @@ void HostServices::TestUnitReady()
|
|||
EnterStatusPhase();
|
||||
}
|
||||
|
||||
vector<BYTE> HostServices::InquiryInternal() const
|
||||
vector<byte> HostServices::InquiryInternal() const
|
||||
{
|
||||
return HandleInquiry(device_type::PROCESSOR, scsi_level::SPC_3, false);
|
||||
}
|
||||
|
@ -70,7 +57,7 @@ void HostServices::StartStopUnit()
|
|||
|
||||
if (!start) {
|
||||
// Flush any caches
|
||||
for (Device *device : DeviceFactory::instance().GetAllDevices()) {
|
||||
for (Device *device : device_factory->GetAllDevices()) {
|
||||
device->FlushCache();
|
||||
}
|
||||
|
||||
|
@ -96,14 +83,14 @@ void HostServices::StartStopUnit()
|
|||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
int HostServices::ModeSense6(const DWORD *cdb, BYTE *buf, int max_length)
|
||||
int HostServices::ModeSense6(const vector<int>& cdb, BYTE *buf, int max_length) const
|
||||
{
|
||||
// Block descriptors cannot be returned
|
||||
if (!(cdb[1] & 0x08)) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
auto length = (int)cdb[4];
|
||||
int length = cdb[4];
|
||||
if (length > max_length) {
|
||||
length = max_length;
|
||||
}
|
||||
|
@ -127,7 +114,7 @@ int HostServices::ModeSense6(const DWORD *cdb, BYTE *buf, int max_length)
|
|||
return size;
|
||||
}
|
||||
|
||||
int HostServices::ModeSense10(const DWORD *cdb, BYTE *buf, int max_length)
|
||||
int HostServices::ModeSense10(const vector<int>& cdb, BYTE *buf, int max_length) const
|
||||
{
|
||||
// Block descriptors cannot be returned
|
||||
if (!(cdb[1] & 0x08)) {
|
||||
|
@ -159,33 +146,31 @@ int HostServices::ModeSense10(const DWORD *cdb, BYTE *buf, int max_length)
|
|||
return size;
|
||||
}
|
||||
|
||||
void HostServices::AddModePages(map<int, vector<BYTE>>& pages, int page, bool changeable) const
|
||||
void HostServices::AddModePages(map<int, vector<byte>>& pages, int page, bool changeable) const
|
||||
{
|
||||
if (page == 0x20 || page == 0x3f) {
|
||||
AddRealtimeClockPage(pages, changeable);
|
||||
}
|
||||
}
|
||||
|
||||
void HostServices::AddRealtimeClockPage(map<int, vector<BYTE>>& pages, bool changeable) const
|
||||
void HostServices::AddRealtimeClockPage(map<int, vector<byte>>& pages, bool changeable) const
|
||||
{
|
||||
if (!changeable) {
|
||||
vector<BYTE> buf(10);
|
||||
|
||||
// Data structure version 1.0
|
||||
buf[2] = 0x01;
|
||||
buf[3] = 0x00;
|
||||
|
||||
std::time_t t = std::time(nullptr);
|
||||
tm localtime;
|
||||
localtime_r(&t, &localtime);
|
||||
buf[4] = (BYTE)localtime.tm_year;
|
||||
buf[5] = (BYTE)localtime.tm_mon;
|
||||
buf[6] = (BYTE)localtime.tm_mday;
|
||||
buf[7] = (BYTE)localtime.tm_hour;
|
||||
buf[8] = (BYTE)localtime.tm_min;
|
||||
// Ignore leap second for simplicity
|
||||
buf[9] = (BYTE)(localtime.tm_sec < 60 ? localtime.tm_sec : 59);
|
||||
|
||||
mode_page_datetime datetime;
|
||||
datetime.year = (uint8_t)localtime.tm_year;
|
||||
datetime.month = (uint8_t)localtime.tm_mon;
|
||||
datetime.day = (uint8_t)localtime.tm_mday;
|
||||
datetime.hour = (uint8_t)localtime.tm_hour;
|
||||
datetime.minute = (uint8_t)localtime.tm_min;
|
||||
// Ignore leap second for simplicity
|
||||
datetime.second = (uint8_t)(localtime.tm_sec < 60 ? localtime.tm_sec : 59);
|
||||
|
||||
vector<byte> buf(10);
|
||||
memcpy(&buf[2], &datetime, sizeof(datetime));
|
||||
pages[32] = buf;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,19 +16,21 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
class DeviceFactory;
|
||||
|
||||
class HostServices: public ModePageDevice
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
HostServices();
|
||||
explicit HostServices(const DeviceFactory *);
|
||||
~HostServices() override = default;
|
||||
HostServices(HostServices&) = delete;
|
||||
HostServices& operator=(const HostServices&) = delete;
|
||||
|
||||
bool Dispatch() override;
|
||||
bool Dispatch(scsi_command) override;
|
||||
|
||||
vector<BYTE> InquiryInternal() const override;
|
||||
vector<byte> InquiryInternal() const override;
|
||||
void TestUnitReady() override;
|
||||
void StartStopUnit();
|
||||
|
||||
|
@ -36,16 +38,31 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
void AddModePages(map<int, vector<BYTE>>&, int, bool) const override;
|
||||
void AddModePages(map<int, vector<byte>>&, int, bool) const override;
|
||||
|
||||
private:
|
||||
|
||||
using mode_page_datetime = struct __attribute__((packed)) {
|
||||
// Major and minor version of this data structure (1.0)
|
||||
uint8_t major_version = 0x01;
|
||||
uint8_t minor_version = 0x00;
|
||||
// Current date and time, with daylight savings time adjustment applied
|
||||
uint8_t year; // year - 1900
|
||||
uint8_t month; // 0-11
|
||||
uint8_t day; // 1-31
|
||||
uint8_t hour; // 0-23
|
||||
uint8_t minute; // 0-59
|
||||
uint8_t second; // 0-59
|
||||
};
|
||||
|
||||
using super = ModePageDevice;
|
||||
|
||||
Dispatcher<HostServices> dispatcher;
|
||||
|
||||
int ModeSense6(const DWORD *, BYTE *, int) override;
|
||||
int ModeSense10(const DWORD *, BYTE *, int) override;
|
||||
int ModeSense6(const vector<int>&, BYTE *, int) const override;
|
||||
int ModeSense10(const vector<int>&, BYTE *, int) const override;
|
||||
|
||||
void AddRealtimeClockPage(map<int, vector<BYTE>>&, bool) const;
|
||||
void AddRealtimeClockPage(map<int, vector<byte>>&, bool) const;
|
||||
|
||||
const DeviceFactory *device_factory;
|
||||
};
|
||||
|
|
|
@ -18,19 +18,19 @@ using namespace scsi_defs;
|
|||
|
||||
ModePageDevice::ModePageDevice(const string& id) : PrimaryDevice(id)
|
||||
{
|
||||
dispatcher.AddCommand(eCmdModeSense6, "ModeSense6", &ModePageDevice::ModeSense6);
|
||||
dispatcher.AddCommand(eCmdModeSense10, "ModeSense10", &ModePageDevice::ModeSense10);
|
||||
dispatcher.AddCommand(eCmdModeSelect6, "ModeSelect6", &ModePageDevice::ModeSelect6);
|
||||
dispatcher.AddCommand(eCmdModeSelect10, "ModeSelect10", &ModePageDevice::ModeSelect10);
|
||||
dispatcher.Add(scsi_command::eCmdModeSense6, "ModeSense6", &ModePageDevice::ModeSense6);
|
||||
dispatcher.Add(scsi_command::eCmdModeSense10, "ModeSense10", &ModePageDevice::ModeSense10);
|
||||
dispatcher.Add(scsi_command::eCmdModeSelect6, "ModeSelect6", &ModePageDevice::ModeSelect6);
|
||||
dispatcher.Add(scsi_command::eCmdModeSelect10, "ModeSelect10", &ModePageDevice::ModeSelect10);
|
||||
}
|
||||
|
||||
bool ModePageDevice::Dispatch()
|
||||
bool ModePageDevice::Dispatch(scsi_command cmd)
|
||||
{
|
||||
// The superclass class handles the less specific commands
|
||||
return dispatcher.Dispatch(this, ctrl->cmd[0]) ? true : super::Dispatch();
|
||||
return dispatcher.Dispatch(this, cmd) ? true : super::Dispatch(cmd);
|
||||
}
|
||||
|
||||
int ModePageDevice::AddModePages(const DWORD *cdb, BYTE *buf, int max_length) const
|
||||
int ModePageDevice::AddModePages(const vector<int>& cdb, BYTE *buf, int max_length) const
|
||||
{
|
||||
if (max_length < 0) {
|
||||
return 0;
|
||||
|
@ -44,7 +44,7 @@ int ModePageDevice::AddModePages(const DWORD *cdb, BYTE *buf, int max_length) co
|
|||
LOGTRACE("%s Requesting mode page $%02X", __PRETTY_FUNCTION__, page)
|
||||
|
||||
// Mode page data mapped to the respective page numbers, C++ maps are ordered by key
|
||||
map<int, vector<BYTE>> pages;
|
||||
map<int, vector<byte>> pages;
|
||||
AddModePages(pages, page, changeable);
|
||||
|
||||
if (pages.empty()) {
|
||||
|
@ -53,9 +53,9 @@ int ModePageDevice::AddModePages(const DWORD *cdb, BYTE *buf, int max_length) co
|
|||
}
|
||||
|
||||
// Holds all mode page data
|
||||
vector<BYTE> result;
|
||||
vector<byte> result;
|
||||
|
||||
vector<BYTE> page0;
|
||||
vector<byte> page0;
|
||||
for (auto const& [index, data] : pages) {
|
||||
// The specification mandates that page 0 must be returned after all others
|
||||
if (index) {
|
||||
|
@ -64,9 +64,9 @@ int ModePageDevice::AddModePages(const DWORD *cdb, BYTE *buf, int max_length) co
|
|||
// Page data
|
||||
result.insert(result.end(), data.begin(), data.end());
|
||||
// Page code, PS bit may already have been set
|
||||
result[offset] |= index;
|
||||
result[offset] |= (byte)index;
|
||||
// Page payload size
|
||||
result[offset + 1] = (BYTE)(data.size() - 2);
|
||||
result[offset + 1] = (byte)(data.size() - 2);
|
||||
}
|
||||
else {
|
||||
page0 = data;
|
||||
|
@ -80,7 +80,7 @@ int ModePageDevice::AddModePages(const DWORD *cdb, BYTE *buf, int max_length) co
|
|||
// Page data
|
||||
result.insert(result.end(), page0.begin(), page0.end());
|
||||
// Page payload size
|
||||
result[offset + 1] = (BYTE)(page0.size() - 2);
|
||||
result[offset + 1] = (byte)(page0.size() - 2);
|
||||
}
|
||||
|
||||
// Do not return more than the requested number of bytes
|
||||
|
@ -104,7 +104,7 @@ void ModePageDevice::ModeSense10()
|
|||
EnterDataInPhase();
|
||||
}
|
||||
|
||||
void ModePageDevice::ModeSelect(const DWORD*, const BYTE *, int)
|
||||
void ModePageDevice::ModeSelect(const vector<int>&, const BYTE *, int)
|
||||
{
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
|
||||
}
|
||||
|
|
|
@ -25,16 +25,14 @@ public:
|
|||
ModePageDevice(ModePageDevice&) = delete;
|
||||
ModePageDevice& operator=(const ModePageDevice&) = delete;
|
||||
|
||||
bool Dispatch() override;
|
||||
bool Dispatch(scsi_command) override;
|
||||
|
||||
vector<BYTE> InquiryInternal() const override = 0;
|
||||
|
||||
virtual void ModeSelect(const DWORD *, const BYTE *, int);
|
||||
virtual void ModeSelect(const vector<int>&, const BYTE *, int);
|
||||
|
||||
protected:
|
||||
|
||||
int AddModePages(const DWORD *, BYTE *, int) const;
|
||||
virtual void AddModePages(map<int, vector<BYTE>>&, int, bool) const = 0;
|
||||
int AddModePages(const vector<int>&, BYTE *, int) const;
|
||||
virtual void AddModePages(map<int, vector<byte>>&, int, bool) const = 0;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -42,8 +40,8 @@ private:
|
|||
|
||||
Dispatcher<ModePageDevice> dispatcher;
|
||||
|
||||
virtual int ModeSense6(const DWORD *, BYTE *, int) = 0;
|
||||
virtual int ModeSense10(const DWORD *, BYTE *, int) = 0;
|
||||
virtual int ModeSense6(const vector<int>&, BYTE *, int) const = 0;
|
||||
virtual int ModeSense10(const vector<int>&, BYTE *, int) const = 0;
|
||||
|
||||
void ModeSense6();
|
||||
void ModeSense10();
|
||||
|
|
|
@ -18,17 +18,17 @@ using namespace scsi_defs;
|
|||
PrimaryDevice::PrimaryDevice(const string& id) : ScsiPrimaryCommands(), Device(id)
|
||||
{
|
||||
// Mandatory SCSI primary commands
|
||||
dispatcher.AddCommand(eCmdTestUnitReady, "TestUnitReady", &PrimaryDevice::TestUnitReady);
|
||||
dispatcher.AddCommand(eCmdInquiry, "Inquiry", &PrimaryDevice::Inquiry);
|
||||
dispatcher.AddCommand(eCmdReportLuns, "ReportLuns", &PrimaryDevice::ReportLuns);
|
||||
dispatcher.Add(scsi_command::eCmdTestUnitReady, "TestUnitReady", &PrimaryDevice::TestUnitReady);
|
||||
dispatcher.Add(scsi_command::eCmdInquiry, "Inquiry", &PrimaryDevice::Inquiry);
|
||||
dispatcher.Add(scsi_command::eCmdReportLuns, "ReportLuns", &PrimaryDevice::ReportLuns);
|
||||
|
||||
// Optional commands used by all RaSCSI devices
|
||||
dispatcher.AddCommand(eCmdRequestSense, "RequestSense", &PrimaryDevice::RequestSense);
|
||||
dispatcher.Add(scsi_command::eCmdRequestSense, "RequestSense", &PrimaryDevice::RequestSense);
|
||||
}
|
||||
|
||||
bool PrimaryDevice::Dispatch()
|
||||
bool PrimaryDevice::Dispatch(scsi_command cmd)
|
||||
{
|
||||
return dispatcher.Dispatch(this, ctrl->cmd[0]);
|
||||
return dispatcher.Dispatch(this, cmd);
|
||||
}
|
||||
|
||||
void PrimaryDevice::SetController(AbstractController *c)
|
||||
|
@ -51,7 +51,7 @@ void PrimaryDevice::Inquiry()
|
|||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
vector<BYTE> buf = InquiryInternal();
|
||||
vector<byte> buf = InquiryInternal();
|
||||
|
||||
size_t allocation_length = ctrl->cmd[4] + (ctrl->cmd[3] << 8);
|
||||
if (allocation_length > buf.size()) {
|
||||
|
@ -121,7 +121,7 @@ void PrimaryDevice::RequestSense()
|
|||
ctrl->status = 0x00;
|
||||
}
|
||||
|
||||
vector<BYTE> buf = controller->GetDeviceForLun(lun)->HandleRequestSense();
|
||||
vector<byte> buf = controller->GetDeviceForLun(lun)->HandleRequestSense();
|
||||
|
||||
size_t allocation_length = ctrl->cmd[4];
|
||||
if (allocation_length > buf.size()) {
|
||||
|
@ -160,9 +160,9 @@ void PrimaryDevice::CheckReady()
|
|||
LOGTRACE("%s Device is ready", __PRETTY_FUNCTION__)
|
||||
}
|
||||
|
||||
vector<BYTE> PrimaryDevice::HandleInquiry(device_type type, scsi_level level, bool is_removable) const
|
||||
vector<byte> PrimaryDevice::HandleInquiry(device_type type, scsi_level level, bool is_removable) const
|
||||
{
|
||||
vector<BYTE> buf(0x1F + 5);
|
||||
vector<byte> buf(0x1F + 5);
|
||||
|
||||
// Basic data
|
||||
// buf[0] ... SCSI device type
|
||||
|
@ -170,11 +170,11 @@ vector<BYTE> PrimaryDevice::HandleInquiry(device_type type, scsi_level level, bo
|
|||
// buf[2] ... SCSI compliance level of command system
|
||||
// buf[3] ... SCSI compliance level of Inquiry response
|
||||
// buf[4] ... Inquiry additional data
|
||||
buf[0] = (BYTE)type;
|
||||
buf[1] = is_removable ? 0x80 : 0x00;
|
||||
buf[2] = (BYTE)level;
|
||||
buf[3] = (BYTE)(level >= scsi_level::SCSI_2 ? scsi_level::SCSI_2 : scsi_level::SCSI_1_CCS);
|
||||
buf[4] = 0x1F;
|
||||
buf[0] = (byte)type;
|
||||
buf[1] = (byte)(is_removable ? 0x80 : 0x00);
|
||||
buf[2] = (byte)level;
|
||||
buf[3] = (byte)(level >= scsi_level::SCSI_2 ? scsi_level::SCSI_2 : scsi_level::SCSI_1_CCS);
|
||||
buf[4] = (byte)0x1F;
|
||||
|
||||
// Padded vendor, product, revision
|
||||
memcpy(&buf[8], GetPaddedName().c_str(), 28);
|
||||
|
@ -182,7 +182,7 @@ vector<BYTE> PrimaryDevice::HandleInquiry(device_type type, scsi_level level, bo
|
|||
return buf;
|
||||
}
|
||||
|
||||
vector<BYTE> PrimaryDevice::HandleRequestSense() const
|
||||
vector<byte> PrimaryDevice::HandleRequestSense() const
|
||||
{
|
||||
// Return not ready only if there are no errors
|
||||
if (!GetStatusCode() && !IsReady()) {
|
||||
|
@ -191,15 +191,15 @@ vector<BYTE> PrimaryDevice::HandleRequestSense() const
|
|||
|
||||
// Set 18 bytes including extended sense data
|
||||
|
||||
vector<BYTE> buf(18);
|
||||
vector<byte> buf(18);
|
||||
|
||||
// Current error
|
||||
buf[0] = 0x70;
|
||||
buf[0] = (byte)0x70;
|
||||
|
||||
buf[2] = (BYTE)(GetStatusCode() >> 16);
|
||||
buf[7] = 10;
|
||||
buf[12] = (BYTE)(GetStatusCode() >> 8);
|
||||
buf[13] = (BYTE)GetStatusCode();
|
||||
buf[2] = (byte)(GetStatusCode() >> 16);
|
||||
buf[7] = (byte)10;
|
||||
buf[12] = (byte)(GetStatusCode() >> 8);
|
||||
buf[13] = (byte)GetStatusCode();
|
||||
|
||||
LOGTRACE("%s Status $%02X, Sense Key $%02X, ASC $%02X",__PRETTY_FUNCTION__, ctrl->status, ctrl->buffer[2], ctrl->buffer[12])
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ public:
|
|||
PrimaryDevice(PrimaryDevice&) = delete;
|
||||
PrimaryDevice& operator=(const PrimaryDevice&) = delete;
|
||||
|
||||
bool Dispatch() override;
|
||||
bool Dispatch(scsi_command) override;
|
||||
|
||||
void SetController(AbstractController *);
|
||||
virtual bool WriteByteSequence(BYTE *, uint32_t);
|
||||
|
@ -37,8 +37,8 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
vector<BYTE> HandleInquiry(scsi_defs::device_type, scsi_level, bool) const;
|
||||
virtual vector<BYTE> InquiryInternal() const = 0;
|
||||
vector<byte> HandleInquiry(scsi_defs::device_type, scsi_level, bool) const;
|
||||
virtual vector<byte> InquiryInternal() const = 0;
|
||||
void CheckReady();
|
||||
|
||||
void EnterStatusPhase() { controller->Status(); }
|
||||
|
@ -55,7 +55,7 @@ private:
|
|||
void ReportLuns() override;
|
||||
void Inquiry() override;
|
||||
|
||||
vector<BYTE> HandleRequestSense() const;
|
||||
vector<byte> HandleRequestSense() const;
|
||||
|
||||
Dispatcher<PrimaryDevice> dispatcher;
|
||||
};
|
||||
|
|
|
@ -13,10 +13,12 @@
|
|||
|
||||
using namespace scsi_defs;
|
||||
|
||||
void scsi_command_util::ModeSelect(const DWORD *cdb, const BYTE *buf, int length, int sector_size)
|
||||
void scsi_command_util::ModeSelect(const vector<int>& cdb, const BYTE *buf, int length, int sector_size)
|
||||
{
|
||||
assert(length >= 0);
|
||||
|
||||
int offset = 0;
|
||||
|
||||
// PF
|
||||
if (cdb[1] & 0x10) {
|
||||
bool has_valid_page_code = false;
|
||||
|
@ -31,7 +33,7 @@ void scsi_command_util::ModeSelect(const DWORD *cdb, const BYTE *buf, int length
|
|||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
|
||||
}
|
||||
|
||||
buf += 12;
|
||||
offset += 12;
|
||||
length -= 12;
|
||||
}
|
||||
|
||||
|
@ -39,11 +41,11 @@ void scsi_command_util::ModeSelect(const DWORD *cdb, const BYTE *buf, int length
|
|||
// TODO The length handling is wrong in case of length < size
|
||||
while (length > 0) {
|
||||
// Format device page
|
||||
if (int page = buf[0]; page == 0x03) {
|
||||
if (int page = buf[offset]; page == 0x03) {
|
||||
// With this page the sector size for a subsequent FORMAT can be selected, but only very few
|
||||
// drives support this, e.g FUJITSU M2624S
|
||||
// We are fine as long as the current sector size remains unchanged
|
||||
if (buf[0xc] != (BYTE)(sector_size >> 8) || buf[0xd] != (BYTE)sector_size) {
|
||||
if (buf[offset + 0xc] != (BYTE)(sector_size >> 8) || buf[offset + 0xd] != (BYTE)sector_size) {
|
||||
// With rascsi it is not possible to permanently (by formatting) change the sector size,
|
||||
// because the size is an externally configurable setting only
|
||||
LOGWARN("In order to change the sector size use the -b option when launching rascsi")
|
||||
|
@ -57,9 +59,9 @@ void scsi_command_util::ModeSelect(const DWORD *cdb, const BYTE *buf, int length
|
|||
}
|
||||
|
||||
// Advance to the next page
|
||||
int size = buf[1] + 2;
|
||||
int size = buf[offset + 1] + 2;
|
||||
length -= size;
|
||||
buf += size;
|
||||
offset += size;
|
||||
}
|
||||
|
||||
if (!has_valid_page_code) {
|
||||
|
@ -72,28 +74,28 @@ void scsi_command_util::ModeSelect(const DWORD *cdb, const BYTE *buf, int length
|
|||
}
|
||||
}
|
||||
|
||||
void scsi_command_util::EnrichFormatPage(map<int, vector<BYTE>>& pages, bool changeable, int sector_size)
|
||||
void scsi_command_util::EnrichFormatPage(map<int, vector<byte>>& pages, bool changeable, int sector_size)
|
||||
{
|
||||
if (changeable) {
|
||||
// The sector size is simulated to be changeable, see the MODE SELECT implementation for details
|
||||
vector<BYTE>& format_page = pages[3];
|
||||
format_page[12] = (BYTE)(sector_size >> 8);
|
||||
format_page[13] = (BYTE)sector_size;
|
||||
vector<byte>& format_page = pages[3];
|
||||
format_page[12] = (byte)(sector_size >> 8);
|
||||
format_page[13] = (byte)sector_size;
|
||||
}
|
||||
}
|
||||
|
||||
void scsi_command_util::AddAppleVendorModePage(map<int, vector<BYTE>>& pages, int, bool changeable)
|
||||
void scsi_command_util::AddAppleVendorModePage(map<int, vector<byte>>& pages, bool changeable)
|
||||
{
|
||||
// Page code 48 (30h) - Apple Vendor Mode Page
|
||||
// Needed for SCCD for stock Apple driver support
|
||||
// Needed for SCHD for stock Apple HD SC Setup
|
||||
vector<BYTE> buf(30);
|
||||
vector<byte> buf(30);
|
||||
|
||||
// No changeable area
|
||||
if (!changeable) {
|
||||
BYTE apple_data[] = "APPLE COMPUTER, INC ";
|
||||
memcpy(&buf[2], apple_data, sizeof(apple_data));
|
||||
const char APPLE_DATA[] = "APPLE COMPUTER, INC ";
|
||||
memcpy(&buf[2], APPLE_DATA, sizeof(APPLE_DATA));
|
||||
}
|
||||
|
||||
pages[0x30] = buf;
|
||||
pages[48] = buf;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ using namespace std;
|
|||
|
||||
namespace scsi_command_util
|
||||
{
|
||||
void ModeSelect(const DWORD *, const BYTE *, int, int);
|
||||
void EnrichFormatPage(map<int, vector<BYTE>>&, bool, int);
|
||||
void AddAppleVendorModePage(map<int, vector<BYTE>>&, int, bool);
|
||||
void ModeSelect(const vector<int>&, const BYTE *, int, int);
|
||||
void EnrichFormatPage(map<int, vector<byte>>&, bool, int);
|
||||
void AddAppleVendorModePage(map<int, vector<byte>>&, bool);
|
||||
}
|
||||
|
|
|
@ -32,55 +32,50 @@
|
|||
|
||||
using namespace scsi_defs;
|
||||
|
||||
const BYTE SCSIDaynaPort::m_bcast_addr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
const BYTE SCSIDaynaPort::m_apple_talk_addr[6] = { 0x09, 0x00, 0x07, 0xff, 0xff, 0xff };
|
||||
// const array<byte, 6> SCSIDaynaPort::m_bcast_addr = { byte{0xff}, byte{0xff}, byte{0xff}, byte{0xff}, byte{0xff}, byte{0xff} };
|
||||
// const array<byte, 6> SCSIDaynaPort::m_apple_talk_addr = { byte{0x09}, byte{0x00}, byte{0x07}, byte{0xff}, byte{0xff}, byte{0xff} };
|
||||
|
||||
// TODO Disk should not be the superclass
|
||||
// TODO Disk must not be the superclass
|
||||
SCSIDaynaPort::SCSIDaynaPort() : Disk("SCDP")
|
||||
{
|
||||
dispatcher.AddCommand(eCmdTestUnitReady, "TestUnitReady", &SCSIDaynaPort::TestUnitReady);
|
||||
dispatcher.AddCommand(eCmdRead6, "Read6", &SCSIDaynaPort::Read6);
|
||||
dispatcher.AddCommand(eCmdWrite6, "Write6", &SCSIDaynaPort::Write6);
|
||||
dispatcher.AddCommand(eCmdRetrieveStats, "RetrieveStats", &SCSIDaynaPort::RetrieveStatistics);
|
||||
dispatcher.AddCommand(eCmdSetIfaceMode, "SetIfaceMode", &SCSIDaynaPort::SetInterfaceMode);
|
||||
dispatcher.AddCommand(eCmdSetMcastAddr, "SetMcastAddr", &SCSIDaynaPort::SetMcastAddr);
|
||||
dispatcher.AddCommand(eCmdEnableInterface, "EnableInterface", &SCSIDaynaPort::EnableInterface);
|
||||
dispatcher.Add(scsi_command::eCmdTestUnitReady, "TestUnitReady", &SCSIDaynaPort::TestUnitReady);
|
||||
dispatcher.Add(scsi_command::eCmdRead6, "Read6", &SCSIDaynaPort::Read6);
|
||||
dispatcher.Add(scsi_command::eCmdWrite6, "Write6", &SCSIDaynaPort::Write6);
|
||||
dispatcher.Add(scsi_command::eCmdRetrieveStats, "RetrieveStats", &SCSIDaynaPort::RetrieveStatistics);
|
||||
dispatcher.Add(scsi_command::eCmdSetIfaceMode, "SetIfaceMode", &SCSIDaynaPort::SetInterfaceMode);
|
||||
dispatcher.Add(scsi_command::eCmdSetMcastAddr, "SetMcastAddr", &SCSIDaynaPort::SetMcastAddr);
|
||||
dispatcher.Add(scsi_command::eCmdEnableInterface, "EnableInterface", &SCSIDaynaPort::EnableInterface);
|
||||
}
|
||||
|
||||
SCSIDaynaPort::~SCSIDaynaPort()
|
||||
{
|
||||
// TAP driver release
|
||||
if (m_tap) {
|
||||
m_tap->Cleanup();
|
||||
delete m_tap;
|
||||
}
|
||||
m_tap.Cleanup();
|
||||
}
|
||||
|
||||
bool SCSIDaynaPort::Dispatch()
|
||||
bool SCSIDaynaPort::Dispatch(scsi_command cmd)
|
||||
{
|
||||
// TODO As long as DaynaPort suffers from being a subclass of Disk at least reject MODE SENSE and MODE SELECT
|
||||
if (ctrl->cmd[0] == eCmdModeSense6 || ctrl->cmd[0] == eCmdModeSelect6 ||
|
||||
ctrl->cmd[0] == eCmdModeSense10 || ctrl->cmd[0] == eCmdModeSelect10) {
|
||||
if (cmd == scsi_command::eCmdModeSense6 || cmd == scsi_command::eCmdModeSelect6 ||
|
||||
cmd == scsi_command::eCmdModeSense10 || cmd == scsi_command::eCmdModeSelect10) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The superclass class handles the less specific commands
|
||||
return dispatcher.Dispatch(this, ctrl->cmd[0]) ? true : super::Dispatch();
|
||||
return dispatcher.Dispatch(this, cmd) ? true : super::Dispatch(cmd);
|
||||
}
|
||||
|
||||
bool SCSIDaynaPort::Init(const unordered_map<string, string>& params)
|
||||
{
|
||||
SetParams(params);
|
||||
|
||||
#ifdef __linux__
|
||||
m_tap = new CTapDriver();
|
||||
m_bTapEnable = m_tap->Init(GetParams());
|
||||
m_bTapEnable = m_tap.Init(GetParams());
|
||||
if(!m_bTapEnable){
|
||||
LOGERROR("Unable to open the TAP interface")
|
||||
|
||||
// Not terminating on regular Linux PCs is helpful for testing
|
||||
#if !defined(__x86_64__) && !defined(__X86__)
|
||||
return false;
|
||||
return false;
|
||||
#endif
|
||||
} else {
|
||||
LOGDEBUG("Tap interface created")
|
||||
|
@ -90,39 +85,36 @@ bool SCSIDaynaPort::Init(const unordered_map<string, string>& params)
|
|||
SetReady(true);
|
||||
SetReset(false);
|
||||
|
||||
// Generate MAC Address
|
||||
memset(m_mac_addr, 0x00, 6);
|
||||
|
||||
// if (m_bTapEnable) {
|
||||
// tap->GetMacAddr(m_mac_addr);
|
||||
// m_mac_addr[5]++;
|
||||
// }
|
||||
|
||||
// !!!!!!!!!!!!!!!!! For now, hard code the MAC address. Its annoying when it keeps changing during development!
|
||||
// TODO: Remove this hard-coded address
|
||||
m_mac_addr[0]=0x00;
|
||||
m_mac_addr[1]=0x80;
|
||||
m_mac_addr[2]=0x19;
|
||||
m_mac_addr[3]=0x10;
|
||||
m_mac_addr[4]=0x98;
|
||||
m_mac_addr[5]=0xE3;
|
||||
#endif // linux
|
||||
m_mac_addr[0] = (byte)0x00;
|
||||
m_mac_addr[1] = (byte)0x80;
|
||||
m_mac_addr[2] = (byte)0x19;
|
||||
m_mac_addr[3] = (byte)0x10;
|
||||
m_mac_addr[4] = (byte)0x98;
|
||||
m_mac_addr[5] = (byte)0xE3;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SCSIDaynaPort::Open(const Filepath& path)
|
||||
{
|
||||
m_tap->OpenDump(path);
|
||||
m_tap.OpenDump(path);
|
||||
}
|
||||
|
||||
vector<BYTE> SCSIDaynaPort::InquiryInternal() const
|
||||
vector<byte> SCSIDaynaPort::InquiryInternal() const
|
||||
{
|
||||
vector<BYTE> buf = HandleInquiry(device_type::PROCESSOR, scsi_level::SCSI_2, false);
|
||||
vector<byte> buf = HandleInquiry(device_type::PROCESSOR, scsi_level::SCSI_2, false);
|
||||
|
||||
// The Daynaport driver for the Mac expects 37 bytes: Increase additional length and
|
||||
// add a vendor-specific byte in order to satisfy this driver.
|
||||
buf[4]++;
|
||||
buf.push_back(0);
|
||||
buf[4] = (byte)((int)buf[4] + 1);
|
||||
buf.push_back((byte)0);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
@ -158,7 +150,7 @@ vector<BYTE> SCSIDaynaPort::InquiryInternal() const
|
|||
// - The SCSI/Link apparently has about 6KB buffer space for packets.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int SCSIDaynaPort::Read(const DWORD *cdb, BYTE *buf, uint64_t)
|
||||
int SCSIDaynaPort::Read(const vector<int>& cdb, BYTE *buf, uint64_t)
|
||||
{
|
||||
int rx_packet_size = 0;
|
||||
auto response = (scsi_resp_read_t*)buf;
|
||||
|
@ -183,14 +175,14 @@ int SCSIDaynaPort::Read(const DWORD *cdb, BYTE *buf, uint64_t)
|
|||
|
||||
// The first 2 bytes are reserved for the length of the packet
|
||||
// The next 4 bytes are reserved for a flag field
|
||||
//rx_packet_size = m_tap->Rx(response->data);
|
||||
rx_packet_size = m_tap->Rx(&buf[DAYNAPORT_READ_HEADER_SZ]);
|
||||
//rx_packet_size = m_tap.Rx(response->data);
|
||||
rx_packet_size = m_tap.Rx(&buf[DAYNAPORT_READ_HEADER_SZ]);
|
||||
|
||||
// If we didn't receive anything, return size of 0
|
||||
if (rx_packet_size <= 0) {
|
||||
LOGTRACE("%s No packet received", __PRETTY_FUNCTION__)
|
||||
response->length = 0;
|
||||
response->flags = e_no_more_data;
|
||||
response->flags = read_data_flags_t::e_no_more_data;
|
||||
return DAYNAPORT_READ_HEADER_SZ;
|
||||
}
|
||||
|
||||
|
@ -235,10 +227,10 @@ int SCSIDaynaPort::Read(const DWORD *cdb, BYTE *buf, uint64_t)
|
|||
|
||||
// If there are pending packets to be processed, we'll tell the host that the read
|
||||
// length was 0.
|
||||
if (!m_tap->PendingPackets())
|
||||
if (!m_tap.PendingPackets())
|
||||
{
|
||||
response->length = 0;
|
||||
response->flags = e_no_more_data;
|
||||
response->flags = read_data_flags_t::e_no_more_data;
|
||||
return DAYNAPORT_READ_HEADER_SZ;
|
||||
}
|
||||
}
|
||||
|
@ -246,7 +238,7 @@ int SCSIDaynaPort::Read(const DWORD *cdb, BYTE *buf, uint64_t)
|
|||
// TODO: Need to do some sort of size checking. The buffer can easily overflow, probably.
|
||||
|
||||
// response->length = rx_packet_size;
|
||||
// if(m_tap->PendingPackets()){
|
||||
// if(m_tap.PendingPackets()){
|
||||
// response->flags = e_more_data_available;
|
||||
// } else {
|
||||
// response->flags = e_no_more_data;
|
||||
|
@ -266,7 +258,7 @@ int SCSIDaynaPort::Read(const DWORD *cdb, BYTE *buf, uint64_t)
|
|||
buf[2] = 0;
|
||||
buf[3] = 0;
|
||||
buf[4] = 0;
|
||||
if(m_tap->PendingPackets()){
|
||||
if(m_tap.PendingPackets()){
|
||||
buf[5] = 0x10;
|
||||
} else {
|
||||
buf[5] = 0;
|
||||
|
@ -281,7 +273,7 @@ int SCSIDaynaPort::Read(const DWORD *cdb, BYTE *buf, uint64_t)
|
|||
} // end while
|
||||
|
||||
response->length = 0;
|
||||
response->flags = e_no_more_data;
|
||||
response->flags = read_data_flags_t::e_no_more_data;
|
||||
return DAYNAPORT_READ_HEADER_SZ;
|
||||
}
|
||||
|
||||
|
@ -314,25 +306,25 @@ int SCSIDaynaPort::WriteCheck(uint64_t)
|
|||
// XX XX ... is the actual packet
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool SCSIDaynaPort::WriteBytes(const DWORD *cdb, const BYTE *buf, uint64_t)
|
||||
bool SCSIDaynaPort::WriteBytes(const vector<int>& cdb, const BYTE *buf, uint64_t)
|
||||
{
|
||||
auto data_format = (BYTE)cdb[5];
|
||||
WORD data_length = (WORD)cdb[4] + ((WORD)cdb[3] << 8);
|
||||
int data_format = cdb[5];
|
||||
int data_length = cdb[4] + (cdb[3] << 8);
|
||||
|
||||
if (data_format == 0x00){
|
||||
m_tap->Tx(buf, data_length);
|
||||
m_tap.Tx(buf, data_length);
|
||||
LOGTRACE("%s Transmitted %u bytes (00 format)", __PRETTY_FUNCTION__, data_length)
|
||||
}
|
||||
else if (data_format == 0x80){
|
||||
// The data length is specified in the first 2 bytes of the payload
|
||||
data_length=(WORD)buf[1] + ((WORD)buf[0] << 8);
|
||||
m_tap->Tx(&buf[4], data_length);
|
||||
data_length=buf[1] + (buf[0] << 8);
|
||||
m_tap.Tx(&buf[4], data_length);
|
||||
LOGTRACE("%s Transmitted %u bytes (80 format)", __PRETTY_FUNCTION__, data_length)
|
||||
}
|
||||
else
|
||||
{
|
||||
// LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)command->format)
|
||||
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)data_format)
|
||||
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, data_format)
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -354,7 +346,7 @@ bool SCSIDaynaPort::WriteBytes(const DWORD *cdb, const BYTE *buf, uint64_t)
|
|||
// - long #3: frames lost
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int SCSIDaynaPort::RetrieveStats(const DWORD *cdb, BYTE *buffer) const
|
||||
int SCSIDaynaPort::RetrieveStats(const vector<int>& cdb, BYTE *buffer) const
|
||||
{
|
||||
int allocation_length = cdb[4] + (cdb[3] << 8);
|
||||
|
||||
|
@ -395,21 +387,21 @@ int SCSIDaynaPort::RetrieveStats(const DWORD *cdb, BYTE *buffer) const
|
|||
// seconds
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool SCSIDaynaPort::EnableInterface(const DWORD *cdb)
|
||||
bool SCSIDaynaPort::EnableInterface(const vector<int>& cdb)
|
||||
{
|
||||
bool result;
|
||||
if (cdb[5] & 0x80) {
|
||||
result = m_tap->Enable();
|
||||
result = m_tap.Enable();
|
||||
if (result) {
|
||||
LOGINFO("The DaynaPort interface has been ENABLED.")
|
||||
}
|
||||
else{
|
||||
LOGWARN("Unable to enable the DaynaPort Interface")
|
||||
}
|
||||
m_tap->Flush();
|
||||
m_tap.Flush();
|
||||
}
|
||||
else {
|
||||
result = m_tap->Disable();
|
||||
result = m_tap.Disable();
|
||||
if (result) {
|
||||
LOGINFO("The DaynaPort interface has been DISABLED.")
|
||||
}
|
||||
|
@ -444,10 +436,10 @@ void SCSIDaynaPort::Read6()
|
|||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
LOGTRACE("%s READ(6) command record=%d blocks=%d", __PRETTY_FUNCTION__, (unsigned int)record, (int)ctrl->blocks)
|
||||
LOGTRACE("%s READ(6) command record=%d blocks=%d", __PRETTY_FUNCTION__, record, ctrl->blocks)
|
||||
|
||||
ctrl->length = Read(ctrl->cmd, ctrl->buffer, record);
|
||||
LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, (int)ctrl->length)
|
||||
LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, ctrl->length)
|
||||
|
||||
// Set next block
|
||||
ctrl->next = record + 1;
|
||||
|
@ -464,18 +456,18 @@ void SCSIDaynaPort::Write6()
|
|||
ctrl->bufsize = DAYNAPORT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
DWORD data_format = ctrl->cmd[5];
|
||||
int data_format = ctrl->cmd[5];
|
||||
|
||||
if(data_format == 0x00) {
|
||||
ctrl->length = (WORD)ctrl->cmd[4] + ((WORD)ctrl->cmd[3] << 8);
|
||||
ctrl->length = ctrl->cmd[4] + (ctrl->cmd[3] << 8);
|
||||
}
|
||||
else if (data_format == 0x80) {
|
||||
ctrl->length = (WORD)ctrl->cmd[4] + ((WORD)ctrl->cmd[3] << 8) + 8;
|
||||
ctrl->length = ctrl->cmd[4] + (ctrl->cmd[3] << 8) + 8;
|
||||
}
|
||||
else {
|
||||
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)data_format)
|
||||
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, data_format)
|
||||
}
|
||||
LOGTRACE("%s length: %04X (%d) format: %02X", __PRETTY_FUNCTION__, (unsigned int)ctrl->length, (int)ctrl->length, (unsigned int)data_format)
|
||||
LOGTRACE("%s length: %04X (%d) format: %02X", __PRETTY_FUNCTION__, ctrl->length, ctrl->length, data_format)
|
||||
|
||||
if (ctrl->length <= 0) {
|
||||
throw scsi_error_exception();
|
||||
|
@ -531,18 +523,24 @@ void SCSIDaynaPort::SetInterfaceMode()
|
|||
|
||||
ctrl->length = RetrieveStats(ctrl->cmd, ctrl->buffer);
|
||||
switch(ctrl->cmd[5]){
|
||||
case SCSIDaynaPort::CMD_SCSILINK_SETMODE:
|
||||
case CMD_SCSILINK_SETMODE:
|
||||
// TODO Not implemented, do nothing
|
||||
EnterStatusPhase();
|
||||
break;
|
||||
|
||||
case SCSIDaynaPort::CMD_SCSILINK_SETMAC:
|
||||
case CMD_SCSILINK_SETMAC:
|
||||
ctrl->length = 6;
|
||||
EnterDataOutPhase();
|
||||
break;
|
||||
|
||||
case CMD_SCSILINK_STATS:
|
||||
case CMD_SCSILINK_ENABLE:
|
||||
case CMD_SCSILINK_SET:
|
||||
LOGWARN("%s Unsupported SetInterface command received: %02X", __PRETTY_FUNCTION__, ctrl->cmd[5])
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGWARN("%s Unknown SetInterface command received: %02X", __PRETTY_FUNCTION__, (unsigned int)ctrl->cmd[5])
|
||||
LOGWARN("%s Unknown SetInterface command received: %02X", __PRETTY_FUNCTION__, ctrl->cmd[5])
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -551,7 +549,7 @@ void SCSIDaynaPort::SetMcastAddr()
|
|||
{
|
||||
ctrl->length = ctrl->cmd[4];
|
||||
if (ctrl->length == 0) {
|
||||
LOGWARN("%s Not supported SetMcastAddr Command %02X", __PRETTY_FUNCTION__, (WORD)ctrl->cmd[2])
|
||||
LOGWARN("%s Not supported SetMcastAddr Command %02X", __PRETTY_FUNCTION__, ctrl->cmd[2])
|
||||
|
||||
throw scsi_error_exception();
|
||||
}
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
#include "disk.h"
|
||||
#include "ctapdriver.h"
|
||||
#include <string>
|
||||
#include <array>
|
||||
|
||||
using namespace std;
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
|
@ -51,15 +54,15 @@ public:
|
|||
void Open(const Filepath& path) override;
|
||||
|
||||
// Commands
|
||||
vector<BYTE> InquiryInternal() const override;
|
||||
int Read(const DWORD *cdb, BYTE *, uint64_t) override;
|
||||
bool WriteBytes(const DWORD *, const BYTE *, uint64_t);
|
||||
vector<byte> InquiryInternal() const override;
|
||||
int Read(const vector<int>&, BYTE *, uint64_t) override;
|
||||
bool WriteBytes(const vector<int>&, const BYTE *, uint64_t);
|
||||
int WriteCheck(uint64_t block) override;
|
||||
|
||||
int RetrieveStats(const DWORD *cdb, BYTE *buffer) const;
|
||||
bool EnableInterface(const DWORD *cdb);
|
||||
int RetrieveStats(const vector<int>&, BYTE *) const;
|
||||
bool EnableInterface(const vector<int>&);
|
||||
|
||||
void SetMacAddr(const DWORD *cdb, BYTE *buffer); // Set MAC address
|
||||
void SetMacAddr(const vector<int>&, BYTE *); // Set MAC address
|
||||
|
||||
void TestUnitReady() override;
|
||||
void Read6() override;
|
||||
|
@ -70,15 +73,15 @@ public:
|
|||
void EnableInterface();
|
||||
int GetSendDelay() const override;
|
||||
|
||||
bool Dispatch() override;
|
||||
bool Dispatch(scsi_command) override;
|
||||
|
||||
const int DAYNAPORT_BUFFER_SIZE = 0x1000000;
|
||||
static const int DAYNAPORT_BUFFER_SIZE = 0x1000000;
|
||||
|
||||
static const BYTE CMD_SCSILINK_STATS = 0x09;
|
||||
static const BYTE CMD_SCSILINK_ENABLE = 0x0E;
|
||||
static const BYTE CMD_SCSILINK_SET = 0x0C;
|
||||
static const BYTE CMD_SCSILINK_SETMODE = 0x80;
|
||||
static const BYTE CMD_SCSILINK_SETMAC = 0x40;
|
||||
static const int CMD_SCSILINK_STATS = 0x09;
|
||||
static const int CMD_SCSILINK_ENABLE = 0x0E;
|
||||
static const int CMD_SCSILINK_SET = 0x0C;
|
||||
static const int CMD_SCSILINK_SETMAC = 0x40;
|
||||
static const int CMD_SCSILINK_SETMODE = 0x80;
|
||||
|
||||
// When we're reading the Linux tap device, most of the messages will not be for us, so we
|
||||
// need to filter through those. However, we don't want to keep re-reading the packets
|
||||
|
@ -96,15 +99,7 @@ private:
|
|||
|
||||
Dispatcher<SCSIDaynaPort> dispatcher;
|
||||
|
||||
using scsi_cmd_daynaport_write_t = struct __attribute__((packed)) {
|
||||
BYTE operation_code;
|
||||
BYTE misc_cdb_information;
|
||||
BYTE logical_block_address;
|
||||
uint16_t length;
|
||||
BYTE format;
|
||||
};
|
||||
|
||||
enum read_data_flags_t : uint32_t {
|
||||
enum class read_data_flags_t : uint32_t {
|
||||
e_no_more_data = 0x00000000,
|
||||
e_more_data_available = 0x00000001,
|
||||
e_dropped_packets = 0xFFFFFFFF,
|
||||
|
@ -113,32 +108,29 @@ private:
|
|||
using scsi_resp_read_t = struct __attribute__((packed)) {
|
||||
uint32_t length;
|
||||
read_data_flags_t flags;
|
||||
BYTE pad;
|
||||
BYTE data[ETH_FRAME_LEN + sizeof(uint32_t)]; // Frame length + 4 byte CRC
|
||||
byte pad;
|
||||
byte data[ETH_FRAME_LEN + sizeof(uint32_t)]; // Frame length + 4 byte CRC
|
||||
};
|
||||
|
||||
using scsi_resp_link_stats_t = struct __attribute__((packed)) {
|
||||
BYTE mac_address[6];
|
||||
byte mac_address[6];
|
||||
uint32_t frame_alignment_errors;
|
||||
uint32_t crc_errors;
|
||||
uint32_t frames_lost;
|
||||
};
|
||||
|
||||
scsi_resp_link_stats_t m_scsi_link_stats = {
|
||||
.mac_address = { 0x00, 0x80, 0x19, 0x10, 0x98, 0xE3 },//MAC address of @PotatoFi's DayanPort
|
||||
//MAC address of @PotatoFi's DayanPort
|
||||
.mac_address = { byte{0x00}, byte{0x80}, byte{0x19}, byte{0x10}, byte{0x98}, byte{0xE3} },
|
||||
.frame_alignment_errors = 0,
|
||||
.crc_errors = 0,
|
||||
.frames_lost = 0,
|
||||
};
|
||||
|
||||
const BYTE m_daynacom_mac_prefix[3] = { 0x00, 0x80, 0x19 };
|
||||
CTapDriver m_tap;
|
||||
|
||||
CTapDriver *m_tap = nullptr;
|
||||
// TAP driver
|
||||
// TAP valid flag
|
||||
bool m_bTapEnable = false;
|
||||
// TAP valid flag
|
||||
BYTE m_mac_addr[6];
|
||||
// MAC Address
|
||||
static const BYTE m_bcast_addr[6];
|
||||
static const BYTE m_apple_talk_addr[6];
|
||||
|
||||
array<byte, 6> m_mac_addr;
|
||||
};
|
||||
|
|
|
@ -29,18 +29,15 @@ SCSIBR::SCSIBR() : Disk("SCBR"), fs(new CFileSys())
|
|||
// Create host file system
|
||||
fs->Reset();
|
||||
|
||||
dispatcher.AddCommand(eCmdTestUnitReady, "TestUnitReady", &SCSIBR::TestUnitReady);
|
||||
dispatcher.AddCommand(eCmdRead6, "GetMessage10", &SCSIBR::GetMessage10);
|
||||
dispatcher.AddCommand(eCmdWrite6, "SendMessage10", &SCSIBR::SendMessage10);
|
||||
dispatcher.Add(scsi_command::eCmdTestUnitReady, "TestUnitReady", &SCSIBR::TestUnitReady);
|
||||
dispatcher.Add(scsi_command::eCmdRead6, "GetMessage10", &SCSIBR::GetMessage10);
|
||||
dispatcher.Add(scsi_command::eCmdWrite6, "SendMessage10", &SCSIBR::SendMessage10);
|
||||
}
|
||||
|
||||
SCSIBR::~SCSIBR()
|
||||
{
|
||||
// TAP driver release
|
||||
if (tap) {
|
||||
tap->Cleanup();
|
||||
delete tap;
|
||||
}
|
||||
tap.Cleanup();
|
||||
|
||||
// Release host file system
|
||||
fs->Reset();
|
||||
|
@ -53,8 +50,7 @@ bool SCSIBR::Init(const unordered_map<string, string>& params)
|
|||
|
||||
#ifdef __linux__
|
||||
// TAP Driver Generation
|
||||
tap = new CTapDriver();
|
||||
m_bTapEnable = tap->Init(GetParams());
|
||||
m_bTapEnable = tap.Init(GetParams());
|
||||
if (!m_bTapEnable){
|
||||
LOGERROR("Unable to open the TAP interface")
|
||||
return false;
|
||||
|
@ -63,7 +59,7 @@ bool SCSIBR::Init(const unordered_map<string, string>& params)
|
|||
// Generate MAC Address
|
||||
memset(mac_addr, 0x00, 6);
|
||||
if (m_bTapEnable) {
|
||||
tap->GetMacAddr(mac_addr);
|
||||
tap.GetMacAddr(mac_addr);
|
||||
mac_addr[5]++;
|
||||
}
|
||||
|
||||
|
@ -73,7 +69,7 @@ bool SCSIBR::Init(const unordered_map<string, string>& params)
|
|||
|
||||
SetReady(m_bTapEnable);
|
||||
|
||||
// Not terminating on regular Linux PCs is helpful for testing
|
||||
// Not terminating on regular Linux PCs is helpful for testing
|
||||
#if defined(__x86_64__) || defined(__X86__)
|
||||
return true;
|
||||
#else
|
||||
|
@ -81,32 +77,32 @@ bool SCSIBR::Init(const unordered_map<string, string>& params)
|
|||
#endif
|
||||
}
|
||||
|
||||
bool SCSIBR::Dispatch()
|
||||
bool SCSIBR::Dispatch(scsi_command cmd)
|
||||
{
|
||||
// The superclass class handles the less specific commands
|
||||
return dispatcher.Dispatch(this, ctrl->cmd[0]) ? true : super::Dispatch();
|
||||
return dispatcher.Dispatch(this, cmd) ? true : super::Dispatch(cmd);
|
||||
}
|
||||
|
||||
vector<BYTE> SCSIBR::InquiryInternal() const
|
||||
vector<byte> SCSIBR::InquiryInternal() const
|
||||
{
|
||||
vector<BYTE> b = HandleInquiry(device_type::COMMUNICATIONS, scsi_level::SCSI_2, false);
|
||||
vector<byte> b = HandleInquiry(device_type::COMMUNICATIONS, scsi_level::SCSI_2, false);
|
||||
|
||||
// The bridge returns 6 more additional bytes than the other devices
|
||||
auto buf = vector<BYTE>(0x1F + 8 + 5);
|
||||
auto buf = vector<byte>(0x1F + 8 + 5);
|
||||
memcpy(buf.data(), b.data(), b.size());
|
||||
|
||||
buf[4] = 0x1F + 8;
|
||||
buf[4] = byte{0x1F + 8};
|
||||
|
||||
// Optional function valid flag
|
||||
buf[36] = '0';
|
||||
buf[36] = byte{'0'};
|
||||
|
||||
// TAP Enable
|
||||
if (m_bTapEnable) {
|
||||
buf[37] = '1';
|
||||
buf[37] = byte{'1'};
|
||||
}
|
||||
|
||||
// CFileSys Enable
|
||||
buf[38] = '1';
|
||||
buf[38] = byte{'1'};
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
@ -117,7 +113,7 @@ void SCSIBR::TestUnitReady()
|
|||
EnterStatusPhase();
|
||||
}
|
||||
|
||||
int SCSIBR::GetMessage10(const DWORD *cdb, BYTE *buf)
|
||||
int SCSIBR::GetMessage10(const vector<int>& cdb, BYTE *buf)
|
||||
{
|
||||
// Type
|
||||
int type = cdb[2];
|
||||
|
@ -209,7 +205,7 @@ int SCSIBR::GetMessage10(const DWORD *cdb, BYTE *buf)
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool SCSIBR::WriteBytes(const DWORD *cdb, BYTE *buf, uint64_t)
|
||||
bool SCSIBR::WriteBytes(const vector<int>& cdb, BYTE *buf, uint64_t)
|
||||
{
|
||||
// Type
|
||||
int type = cdb[2];
|
||||
|
@ -341,15 +337,13 @@ void SCSIBR::ReceivePacket()
|
|||
{
|
||||
static const BYTE bcast_addr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
assert(tap);
|
||||
|
||||
// previous packet has not been received
|
||||
if (packet_enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Receive packet
|
||||
packet_len = tap->Rx(packet_buf);
|
||||
packet_len = tap.Rx(packet_buf);
|
||||
|
||||
// Check if received packet
|
||||
if (memcmp(packet_buf, mac_addr, 6) != 0 && memcmp(packet_buf, bcast_addr, 6) != 0) {
|
||||
|
@ -371,8 +365,6 @@ void SCSIBR::ReceivePacket()
|
|||
|
||||
void SCSIBR::GetPacketBuf(BYTE *buf)
|
||||
{
|
||||
assert(tap);
|
||||
|
||||
// Size limit
|
||||
int len = packet_len;
|
||||
if (len > 2048) {
|
||||
|
@ -388,9 +380,7 @@ void SCSIBR::GetPacketBuf(BYTE *buf)
|
|||
|
||||
void SCSIBR::SendPacket(const BYTE *buf, int len)
|
||||
{
|
||||
assert(tap);
|
||||
|
||||
tap->Tx(buf, len);
|
||||
tap.Tx(buf, len);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -611,7 +601,7 @@ void SCSIBR::FS_Create(BYTE *buf)
|
|||
DWORD nAttribute = ntohl(*dp);
|
||||
i += sizeof(DWORD);
|
||||
|
||||
auto bp = (BOOL*)&buf[i];
|
||||
auto bp = (int*)&buf[i];
|
||||
DWORD bForce = ntohl(*bp);
|
||||
|
||||
pFcb->fileptr = ntohl(pFcb->fileptr);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "os.h"
|
||||
#include "disk.h"
|
||||
#include "ctapdriver.h"
|
||||
#include <string>
|
||||
|
||||
//===========================================================================
|
||||
|
@ -26,7 +27,6 @@
|
|||
// SCSI Host Bridge
|
||||
//
|
||||
//===========================================================================
|
||||
class CTapDriver;
|
||||
class CFileSys;
|
||||
|
||||
class SCSIBR : public Disk
|
||||
|
@ -40,12 +40,12 @@ public:
|
|||
SCSIBR& operator=(const SCSIBR&) = delete;
|
||||
|
||||
bool Init(const unordered_map<string, string>&) override;
|
||||
bool Dispatch() override;
|
||||
bool Dispatch(scsi_command) override;
|
||||
|
||||
// Commands
|
||||
vector<BYTE> InquiryInternal() const override;
|
||||
int GetMessage10(const DWORD *, BYTE *);
|
||||
bool WriteBytes(const DWORD *, BYTE *, uint64_t);
|
||||
vector<byte> InquiryInternal() const override;
|
||||
int GetMessage10(const vector<int>&, BYTE *);
|
||||
bool WriteBytes(const vector<int>&, BYTE *, uint64_t);
|
||||
void TestUnitReady() override;
|
||||
void GetMessage10();
|
||||
void SendMessage10();
|
||||
|
@ -62,7 +62,7 @@ private:
|
|||
void GetPacketBuf(BYTE *buf); // Get a packet
|
||||
void SendPacket(const BYTE *buf, int len); // Send a packet
|
||||
|
||||
CTapDriver *tap = nullptr; // TAP driver
|
||||
CTapDriver tap; // TAP driver
|
||||
bool m_bTapEnable = false; // TAP valid flag
|
||||
BYTE mac_addr[6]; // MAC Addres
|
||||
int packet_len = 0; // Receive packet size
|
||||
|
|
|
@ -50,13 +50,13 @@ using namespace ras_util;
|
|||
|
||||
SCSIPrinter::SCSIPrinter() : PrimaryDevice("SCLP"), ScsiPrinterCommands()
|
||||
{
|
||||
dispatcher.AddCommand(eCmdTestUnitReady, "TestUnitReady", &SCSIPrinter::TestUnitReady);
|
||||
dispatcher.AddCommand(eCmdReserve6, "ReserveUnit", &SCSIPrinter::ReserveUnit);
|
||||
dispatcher.AddCommand(eCmdRelease6, "ReleaseUnit", &SCSIPrinter::ReleaseUnit);
|
||||
dispatcher.AddCommand(eCmdWrite6, "Print", &SCSIPrinter::Print);
|
||||
dispatcher.AddCommand(eCmdSynchronizeBuffer, "SynchronizeBuffer", &SCSIPrinter::SynchronizeBuffer);
|
||||
dispatcher.AddCommand(eCmdSendDiag, "SendDiagnostic", &SCSIPrinter::SendDiagnostic);
|
||||
dispatcher.AddCommand(eCmdStartStop, "StopPrint", &SCSIPrinter::StopPrint);
|
||||
dispatcher.Add(scsi_command::eCmdTestUnitReady, "TestUnitReady", &SCSIPrinter::TestUnitReady);
|
||||
dispatcher.Add(scsi_command::eCmdReserve6, "ReserveUnit", &SCSIPrinter::ReserveUnit);
|
||||
dispatcher.Add(scsi_command::eCmdRelease6, "ReleaseUnit", &SCSIPrinter::ReleaseUnit);
|
||||
dispatcher.Add(scsi_command::eCmdWrite6, "Print", &SCSIPrinter::Print);
|
||||
dispatcher.Add(scsi_command::eCmdSynchronizeBuffer, "SynchronizeBuffer", &SCSIPrinter::SynchronizeBuffer);
|
||||
dispatcher.Add(scsi_command::eCmdSendDiag, "SendDiagnostic", &SCSIPrinter::SendDiagnostic);
|
||||
dispatcher.Add(scsi_command::eCmdStartStop, "StopPrint", &SCSIPrinter::StopPrint);
|
||||
}
|
||||
|
||||
SCSIPrinter::~SCSIPrinter()
|
||||
|
@ -81,10 +81,10 @@ bool SCSIPrinter::Init(const unordered_map<string, string>& params)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SCSIPrinter::Dispatch()
|
||||
bool SCSIPrinter::Dispatch(scsi_command cmd)
|
||||
{
|
||||
// The superclass class handles the less specific commands
|
||||
return dispatcher.Dispatch(this, ctrl->cmd[0]) ? true : super::Dispatch();
|
||||
return dispatcher.Dispatch(this, cmd) ? true : super::Dispatch(cmd);
|
||||
}
|
||||
|
||||
void SCSIPrinter::TestUnitReady()
|
||||
|
@ -94,7 +94,7 @@ void SCSIPrinter::TestUnitReady()
|
|||
EnterStatusPhase();
|
||||
}
|
||||
|
||||
vector<BYTE> SCSIPrinter::InquiryInternal() const
|
||||
vector<byte> SCSIPrinter::InquiryInternal() const
|
||||
{
|
||||
return HandleInquiry(device_type::PRINTER, scsi_level::SCSI_2, false);
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ void SCSIPrinter::Print()
|
|||
length <<= 8;
|
||||
length |= ctrl->cmd[4];
|
||||
|
||||
LOGTRACE("Receiving %d bytes to be printed", length)
|
||||
LOGTRACE("Receiving %d byte(s) to be printed", length)
|
||||
|
||||
// TODO This device suffers from the statically allocated buffer size,
|
||||
// see https://github.com/akuker/RASCSI/issues/669
|
||||
|
@ -222,14 +222,14 @@ bool SCSIPrinter::WriteByteSequence(BYTE *buf, uint32_t length)
|
|||
strcpy(filename, TMP_FILE_PATTERN);
|
||||
fd = mkstemp(filename);
|
||||
if (fd == -1) {
|
||||
LOGERROR("Can't create printer output file: %s", strerror(errno))
|
||||
LOGERROR("Can't create printer output file '%s': %s", filename, strerror(errno))
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGTRACE("Created printer output file '%s'", filename)
|
||||
}
|
||||
|
||||
LOGTRACE("Appending %d byte(s) to printer output file", length)
|
||||
LOGTRACE("Appending %d byte(s) to printer output file '%s'", length, filename)
|
||||
|
||||
auto num_written = (uint32_t)write(fd, buf, length);
|
||||
|
||||
|
|
|
@ -31,11 +31,11 @@ public:
|
|||
SCSIPrinter(SCSIPrinter&) = delete;
|
||||
SCSIPrinter& operator=(const SCSIPrinter&) = delete;
|
||||
|
||||
bool Dispatch() override;
|
||||
bool Dispatch(scsi_command) override;
|
||||
|
||||
bool Init(const unordered_map<string, string>&) override;
|
||||
|
||||
vector<BYTE> InquiryInternal() const override;
|
||||
vector<byte> InquiryInternal() const override;
|
||||
void TestUnitReady() override;
|
||||
void ReserveUnit() override;
|
||||
void ReleaseUnit() override;
|
||||
|
@ -55,7 +55,7 @@ private:
|
|||
|
||||
Dispatcher<SCSIPrinter> dispatcher;
|
||||
|
||||
char filename[TMP_FILENAME_LENGTH + 1];
|
||||
char filename[TMP_FILENAME_LENGTH + 1]; //NOSONAR mkstemp() requires a modifiable string
|
||||
int fd = -1;
|
||||
|
||||
int reserving_initiator = NOT_RESERVED;
|
||||
|
|
|
@ -112,7 +112,7 @@ int CDTrack::GetTrackNo() const
|
|||
//---------------------------------------------------------------------------
|
||||
bool CDTrack::IsValid(DWORD lba) const
|
||||
{
|
||||
// FALSE if the track itself is invalid
|
||||
// false if the track itself is invalid
|
||||
if (!valid) {
|
||||
return false;
|
||||
}
|
||||
|
@ -131,11 +131,6 @@ bool CDTrack::IsValid(DWORD lba) const
|
|||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Is audio track
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool CDTrack::IsAudio() const
|
||||
{
|
||||
assert(valid);
|
||||
|
@ -143,18 +138,12 @@ bool CDTrack::IsAudio() const
|
|||
return audio;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// SCSI CD-ROM
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
SCSICD::SCSICD(const unordered_set<uint32_t>& sector_sizes) : Disk("SCCD"), ScsiMmcCommands(), FileSupport()
|
||||
{
|
||||
SetSectorSizes(sector_sizes);
|
||||
|
||||
dispatcher.AddCommand(eCmdReadToc, "ReadToc", &SCSICD::ReadToc);
|
||||
dispatcher.AddCommand(eCmdGetEventStatusNotification, "GetEventStatusNotification", &SCSICD::GetEventStatusNotification);
|
||||
dispatcher.Add(scsi_command::eCmdReadToc, "ReadToc", &SCSICD::ReadToc);
|
||||
dispatcher.Add(scsi_command::eCmdGetEventStatusNotification, "GetEventStatusNotification", &SCSICD::GetEventStatusNotification);
|
||||
}
|
||||
|
||||
SCSICD::~SCSICD()
|
||||
|
@ -162,10 +151,10 @@ SCSICD::~SCSICD()
|
|||
ClearTrack();
|
||||
}
|
||||
|
||||
bool SCSICD::Dispatch()
|
||||
bool SCSICD::Dispatch(scsi_command cmd)
|
||||
{
|
||||
// The superclass class handles the less specific commands
|
||||
return dispatcher.Dispatch(this, ctrl->cmd[0]) ? true : super::Dispatch();
|
||||
return dispatcher.Dispatch(this, cmd) ? true : super::Dispatch(cmd);
|
||||
}
|
||||
|
||||
void SCSICD::Open(const Filepath& path)
|
||||
|
@ -179,7 +168,7 @@ void SCSICD::Open(const Filepath& path)
|
|||
|
||||
// Open as read-only
|
||||
Fileio fio;
|
||||
if (!fio.Open(path, Fileio::ReadOnly)) {
|
||||
if (!fio.Open(path, Fileio::OpenMode::ReadOnly)) {
|
||||
throw file_not_found_exception("Can't open CD-ROM file");
|
||||
}
|
||||
|
||||
|
@ -195,14 +184,14 @@ void SCSICD::Open(const Filepath& path)
|
|||
OpenPhysical(path);
|
||||
} else {
|
||||
// Get file size
|
||||
if (off_t size = fio.GetFileSize(); size <= 4) {
|
||||
if (fio.GetFileSize() < 4) {
|
||||
fio.Close();
|
||||
throw io_exception("CD-ROM file size must be at least 4 bytes");
|
||||
}
|
||||
|
||||
// Judge whether it is a CUE sheet or an ISO file
|
||||
TCHAR file[5];
|
||||
fio.Read(file, 4);
|
||||
fio.Read((BYTE *)file, 4);
|
||||
file[4] = '\0';
|
||||
fio.Close();
|
||||
|
||||
|
@ -223,7 +212,6 @@ void SCSICD::Open(const Filepath& path)
|
|||
FileSupport::SetPath(path);
|
||||
|
||||
// Set RAW flag
|
||||
assert(disk.dcache);
|
||||
disk.dcache->SetRawMode(rawfile);
|
||||
|
||||
// Attention if ready
|
||||
|
@ -241,7 +229,7 @@ void SCSICD::OpenIso(const Filepath& path)
|
|||
{
|
||||
// Open as read-only
|
||||
Fileio fio;
|
||||
if (!fio.Open(path, Fileio::ReadOnly)) {
|
||||
if (!fio.Open(path, Fileio::OpenMode::ReadOnly)) {
|
||||
throw io_exception("Can't open ISO CD-ROM file");
|
||||
}
|
||||
|
||||
|
@ -301,7 +289,7 @@ void SCSICD::OpenIso(const Filepath& path)
|
|||
// Create only one data track
|
||||
assert(!tracks.size());
|
||||
auto track = make_unique<CDTrack>();
|
||||
track->Init(1, 0, GetBlockCount() - 1);
|
||||
track->Init(1, 0, (int)GetBlockCount() - 1);
|
||||
track->SetPath(false, path);
|
||||
tracks.push_back(move(track));
|
||||
dataindex = 0;
|
||||
|
@ -311,7 +299,7 @@ void SCSICD::OpenPhysical(const Filepath& path)
|
|||
{
|
||||
// Open as read-only
|
||||
Fileio fio;
|
||||
if (!fio.Open(path, Fileio::ReadOnly)) {
|
||||
if (!fio.Open(path, Fileio::OpenMode::ReadOnly)) {
|
||||
throw io_exception("Can't open CD-ROM file");
|
||||
}
|
||||
|
||||
|
@ -334,7 +322,7 @@ void SCSICD::OpenPhysical(const Filepath& path)
|
|||
// Create only one data track
|
||||
ASSERT(!tracks.size());
|
||||
auto track = make_unique<CDTrack>();
|
||||
track->Init(1, 0, GetBlockCount() - 1);
|
||||
track->Init(1, 0, (int)GetBlockCount() - 1);
|
||||
track->SetPath(false, path);
|
||||
tracks.push_back(move(track));
|
||||
dataindex = 0;
|
||||
|
@ -347,35 +335,12 @@ void SCSICD::ReadToc()
|
|||
EnterDataInPhase();
|
||||
}
|
||||
|
||||
vector<BYTE> SCSICD::InquiryInternal() const
|
||||
vector<byte> SCSICD::InquiryInternal() const
|
||||
{
|
||||
return HandleInquiry(device_type::CD_ROM, scsi_level::SCSI_2, true);
|
||||
|
||||
//
|
||||
// The following code worked with the modified Apple CD-ROM drivers. Need to
|
||||
// test with the original code to see if it works as well....
|
||||
// buf[4] = 42; // Required
|
||||
//
|
||||
// // Fill with blanks
|
||||
// memset(&buf[8], 0x20, buf[4] - 3);
|
||||
//
|
||||
// // Vendor name
|
||||
// memcpy(&buf[8], BENDER_SIGNATURE, strlen(BENDER_SIGNATURE));
|
||||
//
|
||||
// // Product name
|
||||
// memcpy(&buf[16], "CD-ROM CDU-8003A", 16);
|
||||
//
|
||||
// // Revision (XM6 version number)
|
||||
//// sprintf(rev, "1.9a",
|
||||
// //// (int)major, (int)(minor >> 4), (int)(minor & 0x0f));
|
||||
// memcpy(&buf[32], "1.9a", 4);
|
||||
//
|
||||
// //strcpy(&buf[35],"A1.9a");
|
||||
// buf[36]=0x20;
|
||||
// memcpy(&buf[37],"1999/01/01",10);
|
||||
}
|
||||
|
||||
void SCSICD::AddModePages(map<int, vector<BYTE>>& pages, int page, bool changeable) const
|
||||
void SCSICD::AddModePages(map<int, vector<byte>>& pages, int page, bool changeable) const
|
||||
{
|
||||
super::AddModePages(pages, page, changeable);
|
||||
|
||||
|
@ -390,26 +355,26 @@ void SCSICD::AddModePages(map<int, vector<BYTE>>& pages, int page, bool changeab
|
|||
}
|
||||
}
|
||||
|
||||
void SCSICD::AddCDROMPage(map<int, vector<BYTE>>& pages, bool changeable) const
|
||||
void SCSICD::AddCDROMPage(map<int, vector<byte>>& pages, bool changeable) const
|
||||
{
|
||||
vector<BYTE> buf(8);
|
||||
vector<byte> buf(8);
|
||||
|
||||
// No changeable area
|
||||
if (!changeable) {
|
||||
// 2 seconds for inactive timer
|
||||
buf[3] = 0x05;
|
||||
buf[3] = (byte)0x05;
|
||||
|
||||
// MSF multiples are 60 and 75 respectively
|
||||
buf[5] = 60;
|
||||
buf[7] = 75;
|
||||
buf[5] = (byte)60;
|
||||
buf[7] = (byte)75;
|
||||
}
|
||||
|
||||
pages[13] = buf;
|
||||
}
|
||||
|
||||
void SCSICD::AddCDDAPage(map<int, vector<BYTE>>& pages, bool) const
|
||||
void SCSICD::AddCDDAPage(map<int, vector<byte>>& pages, bool) const
|
||||
{
|
||||
vector<BYTE> buf(16);
|
||||
vector<byte> buf(16);
|
||||
|
||||
// Audio waits for operation completion and allows
|
||||
// PLAY across multiple tracks
|
||||
|
@ -417,23 +382,23 @@ void SCSICD::AddCDDAPage(map<int, vector<BYTE>>& pages, bool) const
|
|||
pages[14] = buf;
|
||||
}
|
||||
|
||||
void SCSICD::AddVendorPage(map<int, vector<BYTE>>& pages, int page, bool changeable) const
|
||||
void SCSICD::AddVendorPage(map<int, vector<byte>>& pages, int page, bool changeable) const
|
||||
{
|
||||
// Page code 48
|
||||
if (page == 0x30 || page == 0x3f) {
|
||||
scsi_command_util::AddAppleVendorModePage(pages, page, changeable);
|
||||
scsi_command_util::AddAppleVendorModePage(pages, changeable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int SCSICD::Read(const DWORD *cdb, BYTE *buf, uint64_t block)
|
||||
int SCSICD::Read(const vector<int>& cdb, BYTE *buf, uint64_t block)
|
||||
{
|
||||
assert(buf);
|
||||
|
||||
CheckReady();
|
||||
|
||||
// Search for the track
|
||||
int index = SearchTrack(block);
|
||||
int index = SearchTrack((int)block);
|
||||
|
||||
// If invalid, out of range
|
||||
if (index < 0) {
|
||||
|
@ -455,7 +420,7 @@ int SCSICD::Read(const DWORD *cdb, BYTE *buf, uint64_t block)
|
|||
// Recreate the disk cache
|
||||
Filepath path;
|
||||
tracks[index]->GetPath(path);
|
||||
disk.dcache = new DiskCache(path, GetSectorSizeShiftCount(), GetBlockCount());
|
||||
disk.dcache = new DiskCache(path, GetSectorSizeShiftCount(), (uint32_t)GetBlockCount());
|
||||
disk.dcache->SetRawMode(rawfile);
|
||||
|
||||
// Reset data index
|
||||
|
@ -467,9 +432,8 @@ int SCSICD::Read(const DWORD *cdb, BYTE *buf, uint64_t block)
|
|||
return super::Read(cdb, buf, block);
|
||||
}
|
||||
|
||||
int SCSICD::ReadToc(const DWORD *cdb, BYTE *buf)
|
||||
int SCSICD::ReadToc(const vector<int>& cdb, BYTE *buf)
|
||||
{
|
||||
assert(cdb);
|
||||
assert(buf);
|
||||
|
||||
CheckReady();
|
||||
|
@ -489,7 +453,7 @@ int SCSICD::ReadToc(const DWORD *cdb, BYTE *buf)
|
|||
// Get and check the last track number
|
||||
int last = tracks[tracks.size() - 1]->GetTrackNo();
|
||||
// Except for AA
|
||||
if ((int)cdb[6] > last && cdb[6] != 0xaa) {
|
||||
if (cdb[6] > last && cdb[6] != 0xaa) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
|
@ -498,7 +462,7 @@ int SCSICD::ReadToc(const DWORD *cdb, BYTE *buf)
|
|||
if (cdb[6] != 0x00) {
|
||||
// Advance the track until the track numbers match
|
||||
while (tracks[index]) {
|
||||
if ((int)cdb[6] == tracks[index]->GetTrackNo()) {
|
||||
if (cdb[6] == tracks[index]->GetTrackNo()) {
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
|
@ -633,7 +597,7 @@ int SCSICD::SearchTrack(DWORD lba) const
|
|||
// Listen to the track
|
||||
assert(tracks[i]);
|
||||
if (tracks[i]->IsValid(lba)) {
|
||||
return i;
|
||||
return (int)i;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -72,19 +72,19 @@ public:
|
|||
SCSICD(SCSICD&) = delete;
|
||||
SCSICD& operator=(const SCSICD&) = delete;
|
||||
|
||||
bool Dispatch() override;
|
||||
bool Dispatch(scsi_command) override;
|
||||
|
||||
void Open(const Filepath& path) override;
|
||||
|
||||
// Commands
|
||||
vector<BYTE> InquiryInternal() const override;
|
||||
int Read(const DWORD *cdb, BYTE *buf, uint64_t block) override;
|
||||
int ReadToc(const DWORD *cdb, BYTE *buf);
|
||||
vector<byte> InquiryInternal() const override;
|
||||
int Read(const vector<int>&, BYTE *, uint64_t) override;
|
||||
int ReadToc(const vector<int>&, BYTE *);
|
||||
|
||||
protected:
|
||||
|
||||
void AddModePages(map<int, vector<BYTE>>&, int, bool) const override;
|
||||
void AddVendorPage(map<int, vector<BYTE>>&, int, bool) const override;
|
||||
void AddModePages(map<int, vector<byte>>&, int, bool) const override;
|
||||
void AddVendorPage(map<int, vector<byte>>&, int, bool) const override;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -92,8 +92,8 @@ private:
|
|||
|
||||
Dispatcher<SCSICD> dispatcher;
|
||||
|
||||
void AddCDROMPage(map<int, vector<BYTE>>&, bool) const;
|
||||
void AddCDDAPage(map<int, vector<BYTE>>&, bool) const;
|
||||
void AddCDROMPage(map<int, vector<byte>>&, bool) const;
|
||||
void AddCDDAPage(map<int, vector<byte>>&, bool) const;
|
||||
|
||||
// Open
|
||||
void OpenCue(const Filepath& path) const;
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
#include "scsi_command_util.h"
|
||||
#include <sstream>
|
||||
|
||||
static const char *DEFAULT_PRODUCT = "SCSI HD";
|
||||
|
||||
SCSIHD::SCSIHD(const unordered_set<uint32_t>& sector_sizes, bool removable, scsi_defs::scsi_level level)
|
||||
: Disk(removable ? "SCRM" : "SCHD")
|
||||
{
|
||||
|
@ -79,7 +77,7 @@ void SCSIHD::Open(const Filepath& path)
|
|||
|
||||
// Open as read-only
|
||||
Fileio fio;
|
||||
if (!fio.Open(path, Fileio::ReadOnly)) {
|
||||
if (!fio.Open(path, Fileio::OpenMode::ReadOnly)) {
|
||||
throw file_not_found_exception("Can't open SCSI hard disk file");
|
||||
}
|
||||
|
||||
|
@ -97,27 +95,27 @@ void SCSIHD::Open(const Filepath& path)
|
|||
FinalizeSetup(path, size);
|
||||
}
|
||||
|
||||
vector<BYTE> SCSIHD::InquiryInternal() const
|
||||
vector<byte> SCSIHD::InquiryInternal() const
|
||||
{
|
||||
return HandleInquiry(device_type::DIRECT_ACCESS, scsi_level, IsRemovable());
|
||||
}
|
||||
|
||||
void SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
|
||||
void SCSIHD::ModeSelect(const vector<int>& cdb, const BYTE *buf, int length)
|
||||
{
|
||||
scsi_command_util::ModeSelect(cdb, buf, length, 1 << GetSectorSizeShiftCount());
|
||||
}
|
||||
|
||||
void SCSIHD::AddFormatPage(map<int, vector<BYTE>>& pages, bool changeable) const
|
||||
void SCSIHD::AddFormatPage(map<int, vector<byte>>& pages, bool changeable) const
|
||||
{
|
||||
Disk::AddFormatPage(pages, changeable);
|
||||
|
||||
scsi_command_util::EnrichFormatPage(pages, changeable, 1 << GetSectorSizeShiftCount());
|
||||
}
|
||||
|
||||
void SCSIHD::AddVendorPage(map<int, vector<BYTE>>& pages, int page, bool changeable) const
|
||||
void SCSIHD::AddVendorPage(map<int, vector<byte>>& pages, int page, bool changeable) const
|
||||
{
|
||||
// Page code 48
|
||||
if (page == 0x30 || page == 0x3f) {
|
||||
scsi_command_util::AddAppleVendorModePage(pages, page, changeable);
|
||||
scsi_command_util::AddAppleVendorModePage(pages, changeable);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
class SCSIHD : public Disk, public FileSupport
|
||||
{
|
||||
static constexpr const char *DEFAULT_PRODUCT = "SCSI HD";
|
||||
|
||||
public:
|
||||
|
||||
|
@ -35,11 +36,11 @@ public:
|
|||
void Open(const Filepath&) override;
|
||||
|
||||
// Commands
|
||||
vector<BYTE> InquiryInternal() const override;
|
||||
void ModeSelect(const DWORD *cdb, const BYTE *buf, int length) override;
|
||||
vector<byte> InquiryInternal() const override;
|
||||
void ModeSelect(const vector<int>& cdb, const BYTE *buf, int length) override;
|
||||
|
||||
void AddFormatPage(map<int, vector<BYTE>>&, bool) const override;
|
||||
void AddVendorPage(map<int, vector<BYTE>>&, int, bool) const override;
|
||||
void AddFormatPage(map<int, vector<byte>>&, bool) const override;
|
||||
void AddVendorPage(map<int, vector<byte>>&, int, bool) const override;
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -25,9 +25,9 @@ const unordered_set<uint32_t> SCSIHD_NEC::sector_sizes = { 512 };
|
|||
// Extract words that are supposed to be little endian
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
static inline WORD getWordLE(const BYTE *b)
|
||||
static inline int getWordLE(const BYTE *b)
|
||||
{
|
||||
return ((WORD)(b[1]) << 8) | b[0];
|
||||
return (b[1] << 8) | b[0];
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -46,7 +46,7 @@ void SCSIHD_NEC::Open(const Filepath& path)
|
|||
|
||||
// Open as read-only
|
||||
Fileio fio;
|
||||
if (!fio.Open(path, Fileio::ReadOnly)) {
|
||||
if (!fio.Open(path, Fileio::OpenMode::ReadOnly)) {
|
||||
throw file_not_found_exception("Can't open hard disk file");
|
||||
}
|
||||
|
||||
|
@ -55,11 +55,9 @@ void SCSIHD_NEC::Open(const Filepath& path)
|
|||
|
||||
// NEC root sector
|
||||
BYTE root_sector[512];
|
||||
if (size >= (off_t)sizeof(root_sector)) {
|
||||
if (!fio.Read(root_sector, sizeof(root_sector))) {
|
||||
fio.Close();
|
||||
throw io_exception("Can't read NEC hard disk file root sector");
|
||||
}
|
||||
if (size >= (off_t)sizeof(root_sector) && !fio.Read(root_sector, sizeof(root_sector))) {
|
||||
fio.Close();
|
||||
throw io_exception("Can't read NEC hard disk file root sector");
|
||||
}
|
||||
fio.Close();
|
||||
|
||||
|
@ -132,31 +130,31 @@ void SCSIHD_NEC::Open(const Filepath& path)
|
|||
FinalizeSetup(path, size);
|
||||
}
|
||||
|
||||
vector<BYTE> SCSIHD_NEC::InquiryInternal() const
|
||||
vector<byte> SCSIHD_NEC::InquiryInternal() const
|
||||
{
|
||||
return HandleInquiry(device_type::DIRECT_ACCESS, scsi_level::SCSI_1_CCS, false);
|
||||
}
|
||||
|
||||
void SCSIHD_NEC::AddErrorPage(map<int, vector<BYTE>>& pages, bool) const
|
||||
void SCSIHD_NEC::AddErrorPage(map<int, vector<byte>>& pages, bool) const
|
||||
{
|
||||
vector<BYTE> buf(8);
|
||||
vector<byte> buf(8);
|
||||
|
||||
// The retry count is 0, and the limit time uses the default value inside the device.
|
||||
|
||||
pages[1] = buf;
|
||||
}
|
||||
|
||||
void SCSIHD_NEC::AddFormatPage(map<int, vector<BYTE>>& pages, bool changeable) const
|
||||
void SCSIHD_NEC::AddFormatPage(map<int, vector<byte>>& pages, bool changeable) const
|
||||
{
|
||||
vector<BYTE> buf(24);
|
||||
vector<byte> buf(24);
|
||||
|
||||
// Page can be saved
|
||||
buf[0] = 0x80;
|
||||
buf[0] = (byte)0x80;
|
||||
|
||||
// Make the number of bytes in the physical sector appear mutable (although it cannot actually be)
|
||||
if (changeable) {
|
||||
buf[0xc] = 0xff;
|
||||
buf[0xd] = 0xff;
|
||||
buf[0xc] = (byte)0xff;
|
||||
buf[0xd] = (byte)0xff;
|
||||
|
||||
pages[3] = buf;
|
||||
|
||||
|
@ -165,40 +163,40 @@ void SCSIHD_NEC::AddFormatPage(map<int, vector<BYTE>>& pages, bool changeable) c
|
|||
|
||||
if (IsReady()) {
|
||||
// Set the number of tracks in one zone (PC-9801-55 seems to see this value)
|
||||
buf[0x2] = (BYTE)(heads >> 8);
|
||||
buf[0x3] = (BYTE)heads;
|
||||
buf[0x2] = (byte)(heads >> 8);
|
||||
buf[0x3] = (byte)heads;
|
||||
|
||||
// Set the number of sectors per track
|
||||
buf[0xa] = (BYTE)(sectors >> 8);
|
||||
buf[0xb] = (BYTE)sectors;
|
||||
buf[0xa] = (byte)(sectors >> 8);
|
||||
buf[0xb] = (byte)sectors;
|
||||
|
||||
// Set the number of bytes in the physical sector
|
||||
int size = 1 << disk.size;
|
||||
buf[0xc] = (BYTE)(size >> 8);
|
||||
buf[0xd] = (BYTE)size;
|
||||
buf[0xc] = (byte)(size >> 8);
|
||||
buf[0xd] = (byte)size;
|
||||
}
|
||||
|
||||
// Set removable attributes (remains of the old days)
|
||||
if (IsRemovable()) {
|
||||
buf[20] = 0x20;
|
||||
buf[20] = (byte)0x20;
|
||||
}
|
||||
|
||||
pages[3] = buf;
|
||||
}
|
||||
|
||||
void SCSIHD_NEC::AddDrivePage(map<int, vector<BYTE>>& pages, bool changeable) const
|
||||
void SCSIHD_NEC::AddDrivePage(map<int, vector<byte>>& pages, bool changeable) const
|
||||
{
|
||||
vector<BYTE> buf(20);
|
||||
vector<byte> buf(20);
|
||||
|
||||
// No changeable area
|
||||
if (!changeable && IsReady()) {
|
||||
// Set the number of cylinders
|
||||
buf[0x2] = (BYTE)(cylinders >> 16);
|
||||
buf[0x3] = (BYTE)(cylinders >> 8);
|
||||
buf[0x4] = (BYTE)cylinders;
|
||||
buf[0x2] = (byte)(cylinders >> 16);
|
||||
buf[0x3] = (byte)(cylinders >> 8);
|
||||
buf[0x4] = (byte)cylinders;
|
||||
|
||||
// Set the number of heads
|
||||
buf[0x5] = (BYTE)heads;
|
||||
buf[0x5] = (byte)heads;
|
||||
}
|
||||
|
||||
pages[4] = buf;
|
||||
|
|
|
@ -35,11 +35,11 @@ public:
|
|||
|
||||
void Open(const Filepath& path) override;
|
||||
|
||||
vector<BYTE> InquiryInternal() const override;
|
||||
vector<byte> InquiryInternal() const override;
|
||||
|
||||
void AddErrorPage(map<int, vector<BYTE>>&, bool) const override;
|
||||
void AddFormatPage(map<int, vector<BYTE>>&, bool) const override;
|
||||
void AddDrivePage(map<int, vector<BYTE>>&, bool) const override;
|
||||
void AddErrorPage(map<int, vector<byte>>&, bool) const override;
|
||||
void AddFormatPage(map<int, vector<byte>>&, bool) const override;
|
||||
void AddDrivePage(map<int, vector<byte>>&, bool) const override;
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ void SCSIMO::Open(const Filepath& path)
|
|||
// Open as read-only
|
||||
Fileio fio;
|
||||
|
||||
if (!fio.Open(path, Fileio::ReadOnly)) {
|
||||
if (!fio.Open(path, Fileio::OpenMode::ReadOnly)) {
|
||||
throw file_not_found_exception("Can't open MO file");
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ void SCSIMO::Open(const Filepath& path)
|
|||
}
|
||||
}
|
||||
|
||||
vector<BYTE> SCSIMO::InquiryInternal() const
|
||||
vector<byte> SCSIMO::InquiryInternal() const
|
||||
{
|
||||
return HandleInquiry(device_type::OPTICAL_MEMORY, scsi_level::SCSI_2, true);
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ void SCSIMO::SetDeviceParameters(BYTE *buf) const
|
|||
buf[2] = 0x03;
|
||||
}
|
||||
|
||||
void SCSIMO::AddModePages(map<int, vector<BYTE>>& pages, int page, bool changeable) const
|
||||
void SCSIMO::AddModePages(map<int, vector<byte>>& pages, int page, bool changeable) const
|
||||
{
|
||||
Disk::AddModePages(pages, page, changeable);
|
||||
|
||||
|
@ -85,22 +85,22 @@ void SCSIMO::AddModePages(map<int, vector<BYTE>>& pages, int page, bool changeab
|
|||
}
|
||||
}
|
||||
|
||||
void SCSIMO::AddFormatPage(map<int, vector<BYTE>>& pages, bool changeable) const
|
||||
void SCSIMO::AddFormatPage(map<int, vector<byte>>& pages, bool changeable) const
|
||||
{
|
||||
Disk::AddFormatPage(pages, changeable);
|
||||
|
||||
scsi_command_util::EnrichFormatPage(pages, changeable, 1 << GetSectorSizeShiftCount());
|
||||
}
|
||||
|
||||
void SCSIMO::AddOptionPage(map<int, vector<BYTE>>& pages, bool) const
|
||||
void SCSIMO::AddOptionPage(map<int, vector<byte>>& pages, bool) const
|
||||
{
|
||||
vector<BYTE> buf(4);
|
||||
vector<byte> buf(4);
|
||||
pages[6] = buf;
|
||||
|
||||
// Do not report update blocks
|
||||
}
|
||||
|
||||
void SCSIMO::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
|
||||
void SCSIMO::ModeSelect(const vector<int>& cdb, const BYTE *buf, int length)
|
||||
{
|
||||
scsi_command_util::ModeSelect(cdb, buf, length, 1 << GetSectorSizeShiftCount());
|
||||
}
|
||||
|
@ -110,14 +110,14 @@ void SCSIMO::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
|
|||
// Vendor Unique Format Page 20h (MO)
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIMO::AddVendorPage(map<int, vector<BYTE>>& pages, int page, bool changeable) const
|
||||
void SCSIMO::AddVendorPage(map<int, vector<byte>>& pages, int page, bool changeable) const
|
||||
{
|
||||
// Page code 20h
|
||||
if (page != 0x20 && page != 0x3f) {
|
||||
return;
|
||||
}
|
||||
|
||||
vector<BYTE> buf(12);
|
||||
vector<byte> buf(12);
|
||||
|
||||
// No changeable area
|
||||
if (changeable) {
|
||||
|
@ -198,16 +198,16 @@ void SCSIMO::AddVendorPage(map<int, vector<BYTE>>& pages, int page, bool changea
|
|||
}
|
||||
}
|
||||
|
||||
buf[2] = 0; // format mode
|
||||
buf[3] = 0; // type of format
|
||||
buf[4] = (BYTE)(blocks >> 24);
|
||||
buf[5] = (BYTE)(blocks >> 16);
|
||||
buf[6] = (BYTE)(blocks >> 8);
|
||||
buf[7] = (BYTE)blocks;
|
||||
buf[8] = (BYTE)(spare >> 8);
|
||||
buf[9] = (BYTE)spare;
|
||||
buf[10] = (BYTE)(bands >> 8);
|
||||
buf[11] = (BYTE)bands;
|
||||
buf[2] = (byte)0; // format mode
|
||||
buf[3] = (byte)0; // type of format
|
||||
buf[4] = (byte)(blocks >> 24);
|
||||
buf[5] = (byte)(blocks >> 16);
|
||||
buf[6] = (byte)(blocks >> 8);
|
||||
buf[7] = (byte)blocks;
|
||||
buf[8] = (byte)(spare >> 8);
|
||||
buf[9] = (byte)spare;
|
||||
buf[10] = (byte)(bands >> 8);
|
||||
buf[11] = (byte)bands;
|
||||
}
|
||||
|
||||
pages[32] = buf;
|
||||
|
|
|
@ -31,19 +31,19 @@ public:
|
|||
|
||||
void Open(const Filepath& path) override;
|
||||
|
||||
vector<BYTE> InquiryInternal() const override;
|
||||
void ModeSelect(const DWORD *cdb, const BYTE *buf, int length) override;
|
||||
vector<byte> InquiryInternal() const override;
|
||||
void ModeSelect(const vector<int>&, const BYTE *, int) override;
|
||||
|
||||
protected:
|
||||
|
||||
void SetDeviceParameters(BYTE *) const override;
|
||||
void AddModePages(map<int, vector<BYTE>>&, int, bool) const override;
|
||||
void AddFormatPage(map<int, vector<BYTE>>&, bool) const override;
|
||||
void AddVendorPage(map<int, vector<BYTE>>&, int, bool) const override;
|
||||
void AddModePages(map<int, vector<byte>>&, int, bool) const override;
|
||||
void AddFormatPage(map<int, vector<byte>>&, bool) const override;
|
||||
void AddVendorPage(map<int, vector<byte>>&, int, bool) const override;
|
||||
|
||||
private:
|
||||
|
||||
void AddOptionPage(map<int, vector<BYTE>>&, bool) const;
|
||||
void AddOptionPage(map<int, vector<byte>>&, bool) const;
|
||||
|
||||
void SetGeometries(const unordered_map<uint64_t, Geometry>& g) { geometries = g; }
|
||||
bool SetGeometryForCapacity(uint64_t);
|
||||
|
|
|
@ -14,12 +14,6 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// File I/O
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
Fileio::~Fileio()
|
||||
{
|
||||
ASSERT(handle == -1);
|
||||
|
@ -28,184 +22,107 @@ Fileio::~Fileio()
|
|||
Close();
|
||||
}
|
||||
|
||||
BOOL Fileio::Load(const Filepath& path, void *buffer, int size)
|
||||
bool Fileio::Open(const char *fname, OpenMode mode, bool directIO)
|
||||
{
|
||||
ASSERT(buffer);
|
||||
ASSERT(size > 0);
|
||||
ASSERT(handle < 0);
|
||||
|
||||
if (!Open(path, ReadOnly)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!Read(buffer, size)) {
|
||||
Close();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Close();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL Fileio::Save(const Filepath& path, const void *buffer, int size)
|
||||
{
|
||||
ASSERT(buffer);
|
||||
ASSERT(size > 0);
|
||||
ASSERT(handle < 0);
|
||||
|
||||
if (!Open(path, WriteOnly)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!Write(buffer, size)) {
|
||||
Close();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Close();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL Fileio::Open(const char *fname, OpenMode mode, BOOL directIO)
|
||||
{
|
||||
mode_t omode;
|
||||
|
||||
ASSERT(fname);
|
||||
ASSERT(handle < 0);
|
||||
assert(fname);
|
||||
assert(handle < 0);
|
||||
|
||||
// Always fail a read from a null array
|
||||
if (fname[0] == _T('\0')) {
|
||||
handle = -1;
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Default mode
|
||||
omode = directIO ? O_DIRECT : 0;
|
||||
mode_t omode = directIO ? O_DIRECT : 0;
|
||||
|
||||
switch (mode) {
|
||||
case ReadOnly:
|
||||
case OpenMode::ReadOnly:
|
||||
handle = open(fname, O_RDONLY | omode);
|
||||
break;
|
||||
|
||||
case WriteOnly:
|
||||
case OpenMode::WriteOnly:
|
||||
handle = open(fname, O_CREAT | O_WRONLY | O_TRUNC | omode, 0666);
|
||||
break;
|
||||
|
||||
case ReadWrite:
|
||||
case OpenMode::ReadWrite:
|
||||
// Make sure RW does not succeed when reading from CD-ROM
|
||||
if (access(fname, 0x06) != 0) {
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
handle = open(fname, O_RDWR | omode);
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT(FALSE);
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
// Evaluate results
|
||||
if (handle == -1) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ASSERT(handle >= 0);
|
||||
return TRUE;
|
||||
return handle != -1;
|
||||
}
|
||||
|
||||
BOOL Fileio::Open(const char *fname, OpenMode mode)
|
||||
bool Fileio::Open(const char *fname, OpenMode mode)
|
||||
{
|
||||
|
||||
return Open(fname, mode, FALSE);
|
||||
return Open(fname, mode, false);
|
||||
}
|
||||
|
||||
BOOL Fileio::Open(const Filepath& path, OpenMode mode)
|
||||
bool Fileio::Open(const Filepath& path, OpenMode mode)
|
||||
{
|
||||
|
||||
return Open(path.GetPath(), mode);
|
||||
}
|
||||
|
||||
BOOL Fileio::OpenDIO(const char *fname, OpenMode mode)
|
||||
bool Fileio::OpenDIO(const char *fname, OpenMode mode)
|
||||
{
|
||||
|
||||
// Open with included O_DIRECT
|
||||
if (!Open(fname, mode, TRUE)) {
|
||||
if (!Open(fname, mode, true)) {
|
||||
// Normal mode retry (tmpfs etc.)
|
||||
return Open(fname, mode, FALSE);
|
||||
return Open(fname, mode, false);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL Fileio::OpenDIO(const Filepath& path, OpenMode mode)
|
||||
bool Fileio::OpenDIO(const Filepath& path, OpenMode mode)
|
||||
{
|
||||
|
||||
return OpenDIO(path.GetPath(), mode);
|
||||
}
|
||||
|
||||
BOOL Fileio::Read(void *buffer, int size) const
|
||||
bool Fileio::Read(BYTE *buffer, int size) const
|
||||
{
|
||||
long count;
|
||||
assert(buffer);
|
||||
assert(size > 0);
|
||||
assert(handle >= 0);
|
||||
|
||||
ASSERT(buffer);
|
||||
ASSERT(size > 0);
|
||||
ASSERT(handle >= 0);
|
||||
|
||||
count = read(handle, buffer, size);
|
||||
if (count != size) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return read(handle, buffer, size) == size;
|
||||
}
|
||||
|
||||
BOOL Fileio::Write(const void *buffer, int size) const
|
||||
bool Fileio::Write(const BYTE *buffer, int size) const
|
||||
{
|
||||
long count;
|
||||
assert(buffer);
|
||||
assert(size > 0);
|
||||
assert(handle >= 0);
|
||||
|
||||
ASSERT(buffer);
|
||||
ASSERT(size > 0);
|
||||
ASSERT(handle >= 0);
|
||||
|
||||
count = write(handle, buffer, size);
|
||||
if (count != size) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return write(handle, buffer, size) == size;
|
||||
}
|
||||
|
||||
BOOL Fileio::Seek(off_t offset, BOOL relative) const
|
||||
bool Fileio::Seek(off_t offset) const
|
||||
{
|
||||
ASSERT(handle >= 0);
|
||||
ASSERT(offset >= 0);
|
||||
assert(handle >= 0);
|
||||
assert(offset >= 0);
|
||||
|
||||
// Add current position in case of relative seek
|
||||
if (relative) {
|
||||
offset += GetFilePos();
|
||||
}
|
||||
|
||||
if (lseek(handle, offset, SEEK_SET) != offset) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return lseek(handle, offset, SEEK_SET) == offset;
|
||||
}
|
||||
|
||||
off_t Fileio::GetFileSize() const
|
||||
{
|
||||
off_t cur;
|
||||
off_t end;
|
||||
|
||||
ASSERT(handle >= 0);
|
||||
assert(handle >= 0);
|
||||
|
||||
// Get file position in 64bit
|
||||
cur = GetFilePos();
|
||||
off_t cur = GetFilePos();
|
||||
|
||||
// Get file size in64bitで
|
||||
end = lseek(handle, 0, SEEK_END);
|
||||
off_t end = lseek(handle, 0, SEEK_END);
|
||||
|
||||
// Return to start position
|
||||
Seek(cur);
|
||||
|
@ -215,19 +132,14 @@ off_t Fileio::GetFileSize() const
|
|||
|
||||
off_t Fileio::GetFilePos() const
|
||||
{
|
||||
off_t pos;
|
||||
|
||||
ASSERT(handle >= 0);
|
||||
assert(handle >= 0);
|
||||
|
||||
// Get file position in 64bit
|
||||
pos = lseek(handle, 0, SEEK_CUR);
|
||||
return pos;
|
||||
|
||||
return lseek(handle, 0, SEEK_CUR);
|
||||
}
|
||||
|
||||
void Fileio::Close()
|
||||
{
|
||||
|
||||
if (handle != -1) {
|
||||
close(handle);
|
||||
handle = -1;
|
||||
|
|
|
@ -8,35 +8,15 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#if !defined(fileio_h)
|
||||
#define fileio_h
|
||||
#pragma once
|
||||
|
||||
#include "filepath.h"
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Macros (for Load, Save)
|
||||
//
|
||||
//===========================================================================
|
||||
#define PROP_IMPORT(f, p) \
|
||||
if (!f->Read(&(p), sizeof(p))) {\
|
||||
return FALSE;\
|
||||
}\
|
||||
|
||||
#define PROP_EXPORT(f, p) \
|
||||
if (!f->Write(&(p), sizeof(p))) {\
|
||||
return FALSE;\
|
||||
}\
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// File I/O
|
||||
//
|
||||
//===========================================================================
|
||||
class Fileio
|
||||
{
|
||||
public:
|
||||
enum OpenMode {
|
||||
|
||||
enum class OpenMode {
|
||||
ReadOnly,
|
||||
WriteOnly,
|
||||
ReadWrite
|
||||
|
@ -47,25 +27,20 @@ public:
|
|||
Fileio(Fileio&) = delete;
|
||||
Fileio& operator=(const Fileio&) = delete;
|
||||
|
||||
BOOL Load(const Filepath& path, void *buffer, int size); // Load ROM, RAM
|
||||
BOOL Save(const Filepath& path, const void *buffer, int size); // Save RAM
|
||||
|
||||
BOOL Open(const char *fname, OpenMode mode);
|
||||
BOOL Open(const Filepath& path, OpenMode mode);
|
||||
BOOL OpenDIO(const char *fname, OpenMode mode);
|
||||
BOOL OpenDIO(const Filepath& path, OpenMode mode);
|
||||
BOOL Seek(off_t offset, BOOL relative = FALSE) const;
|
||||
BOOL Read(void *buffer, int size) const;
|
||||
BOOL Write(const void *buffer, int size) const;
|
||||
bool Open(const char *fname, OpenMode mode);
|
||||
bool Open(const Filepath& path, OpenMode mode);
|
||||
bool OpenDIO(const Filepath& path, OpenMode mode);
|
||||
bool Seek(off_t offset) const;
|
||||
bool Read(BYTE *buffer, int size) const;
|
||||
bool Write(const BYTE *buffer, int size) const;
|
||||
off_t GetFileSize() const;
|
||||
off_t GetFilePos() const;
|
||||
void Close();
|
||||
BOOL IsValid() const { return (BOOL)(handle != -1); }
|
||||
|
||||
private:
|
||||
BOOL Open(const char *fname, OpenMode mode, BOOL directIO);
|
||||
|
||||
int handle = -1; // File handle
|
||||
bool Open(const char *fname, OpenMode mode, bool directIO);
|
||||
bool OpenDIO(const char *fname, OpenMode mode);
|
||||
|
||||
int handle = -1;
|
||||
};
|
||||
|
||||
#endif // fileio_h
|
||||
|
|
|
@ -77,36 +77,29 @@ DWORD bcm_host_get_peripheral_address(void)
|
|||
|
||||
bool GPIOBUS::Init(mode_e mode)
|
||||
{
|
||||
#if defined(__x86_64__) || defined(__X86__)
|
||||
actmode = mode;
|
||||
|
||||
// When we're running on x86, there is no hardware to talk to, so just return.
|
||||
return true;
|
||||
#else
|
||||
void *map;
|
||||
int i;
|
||||
int j;
|
||||
int pullmode;
|
||||
int fd;
|
||||
#ifdef USE_SEL_EVENT_ENABLE
|
||||
struct epoll_event ev;
|
||||
#endif // USE_SEL_EVENT_ENABLE
|
||||
|
||||
// Save operation mode
|
||||
actmode = mode;
|
||||
|
||||
#if defined(__x86_64__) || defined(__X86__)
|
||||
return true;
|
||||
#else
|
||||
int i;
|
||||
#ifdef USE_SEL_EVENT_ENABLE
|
||||
struct epoll_event ev;
|
||||
#endif
|
||||
|
||||
// Get the base address
|
||||
baseaddr = (DWORD)bcm_host_get_peripheral_address();
|
||||
|
||||
// Open /dev/mem
|
||||
fd = open("/dev/mem", O_RDWR | O_SYNC);
|
||||
int fd = open("/dev/mem", O_RDWR | O_SYNC);
|
||||
if (fd == -1) {
|
||||
LOGERROR("Error: Unable to open /dev/mem. Are you running as root?")
|
||||
return false;
|
||||
}
|
||||
|
||||
// Map peripheral region memory
|
||||
map = mmap(NULL, 0x1000100, PROT_READ | PROT_WRITE, MAP_SHARED, fd, baseaddr);
|
||||
void *map = mmap(NULL, 0x1000100, PROT_READ | PROT_WRITE, MAP_SHARED, fd, baseaddr);
|
||||
if (map == MAP_FAILED) {
|
||||
LOGERROR("Error: Unable to map memory")
|
||||
close(fd);
|
||||
|
@ -166,16 +159,16 @@ bool GPIOBUS::Init(mode_e mode)
|
|||
|
||||
// Set pull up/pull down
|
||||
#if SIGNAL_CONTROL_MODE == 0
|
||||
pullmode = GPIO_PULLNONE;
|
||||
int pullmode = GPIO_PULLNONE;
|
||||
#elif SIGNAL_CONTROL_MODE == 1
|
||||
pullmode = GPIO_PULLUP;
|
||||
int pullmode = GPIO_PULLUP;
|
||||
#else
|
||||
pullmode = GPIO_PULLDOWN;
|
||||
int pullmode = GPIO_PULLDOWN;
|
||||
#endif
|
||||
|
||||
// Initialize all signals
|
||||
for (i = 0; SignalTable[i] >= 0; i++) {
|
||||
j = SignalTable[i];
|
||||
int j = SignalTable[i];
|
||||
PinSetSignal(j, FALSE);
|
||||
PinConfig(j, GPIO_INPUT);
|
||||
PullConfig(j, pullmode);
|
||||
|
@ -305,9 +298,6 @@ void GPIOBUS::Cleanup()
|
|||
#if defined(__x86_64__) || defined(__X86__)
|
||||
return;
|
||||
#else
|
||||
int i;
|
||||
int pin;
|
||||
|
||||
// Release SEL signal interrupt
|
||||
#ifdef USE_SEL_EVENT_ENABLE
|
||||
close(selevreq.fd);
|
||||
|
@ -325,8 +315,8 @@ void GPIOBUS::Cleanup()
|
|||
PinConfig(PIN_DTD, GPIO_INPUT);
|
||||
|
||||
// Initialize all signals
|
||||
for (i = 0; SignalTable[i] >= 0; i++) {
|
||||
pin = SignalTable[i];
|
||||
for (int i = 0; SignalTable[i] >= 0; i++) {
|
||||
int pin = SignalTable[i];
|
||||
PinSetSignal(pin, FALSE);
|
||||
PinConfig(pin, GPIO_INPUT);
|
||||
PullConfig(pin, GPIO_PULLNONE);
|
||||
|
@ -358,7 +348,7 @@ void GPIOBUS::Reset()
|
|||
SetSignal(j, OFF);
|
||||
}
|
||||
|
||||
if (actmode == TARGET) {
|
||||
if (actmode == mode_e::TARGET) {
|
||||
// Target mode
|
||||
|
||||
// Set target signal to input
|
||||
|
@ -438,7 +428,7 @@ void GPIOBUS::SetBSY(bool ast)
|
|||
// Set BSY signal
|
||||
SetSignal(PIN_BSY, ast);
|
||||
|
||||
if (actmode == TARGET) {
|
||||
if (actmode == mode_e::TARGET) {
|
||||
if (ast) {
|
||||
// Turn on ACTIVE signal
|
||||
SetControl(PIN_ACT, ACT_ON);
|
||||
|
@ -474,7 +464,7 @@ bool GPIOBUS::GetSEL() const
|
|||
|
||||
void GPIOBUS::SetSEL(bool ast)
|
||||
{
|
||||
if (actmode == INITIATOR && ast) {
|
||||
if (actmode == mode_e::INITIATOR && ast) {
|
||||
// Turn on ACTIVE signal
|
||||
SetControl(PIN_ACT, ACT_ON);
|
||||
}
|
||||
|
@ -547,7 +537,7 @@ bool GPIOBUS::GetIO()
|
|||
{
|
||||
bool ast = GetSignal(PIN_IO);
|
||||
|
||||
if (actmode == INITIATOR) {
|
||||
if (actmode == mode_e::INITIATOR) {
|
||||
// Change the data input/output direction by IO signal
|
||||
if (ast) {
|
||||
SetControl(PIN_DTD, DTD_IN);
|
||||
|
@ -581,7 +571,7 @@ void GPIOBUS::SetIO(bool ast)
|
|||
{
|
||||
SetSignal(PIN_IO, ast);
|
||||
|
||||
if (actmode == TARGET) {
|
||||
if (actmode == mode_e::TARGET) {
|
||||
// Change the data input/output direction by IO signal
|
||||
if (ast) {
|
||||
SetControl(PIN_DTD, DTD_OUT);
|
||||
|
@ -627,7 +617,7 @@ void GPIOBUS::SetREQ(bool ast)
|
|||
//---------------------------------------------------------------------------
|
||||
BYTE GPIOBUS::GetDAT()
|
||||
{
|
||||
DWORD data = Acquire();
|
||||
uint32_t data = Acquire();
|
||||
data =
|
||||
((data >> (PIN_DT0 - 0)) & (1 << 0)) |
|
||||
((data >> (PIN_DT1 - 1)) & (1 << 1)) |
|
||||
|
@ -692,7 +682,7 @@ bool GPIOBUS::GetDP() const
|
|||
int GPIOBUS::CommandHandShake(BYTE *buf)
|
||||
{
|
||||
// Only works in TARGET mode
|
||||
if (actmode != TARGET) {
|
||||
if (actmode != mode_e::TARGET) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -818,7 +808,7 @@ int GPIOBUS::ReceiveHandShake(BYTE *buf, int count)
|
|||
// Disable IRQs
|
||||
DisableIRQ();
|
||||
|
||||
if (actmode == TARGET) {
|
||||
if (actmode == mode_e::TARGET) {
|
||||
for (i = 0; i < count; i++) {
|
||||
// Assert the REQ signal
|
||||
SetSignal(PIN_REQ, ON);
|
||||
|
@ -918,7 +908,7 @@ int GPIOBUS::SendHandShake(BYTE *buf, int count, int delay_after_bytes)
|
|||
// Disable IRQs
|
||||
DisableIRQ();
|
||||
|
||||
if (actmode == TARGET) {
|
||||
if (actmode == mode_e::TARGET) {
|
||||
for (i = 0; i < count; i++) {
|
||||
if(i==delay_after_bytes){
|
||||
LOGTRACE("%s DELAYING for %dus after %d bytes", __PRETTY_FUNCTION__, SCSI_DELAY_SEND_DATA_DAYNAPORT_US, (int)delay_after_bytes)
|
||||
|
@ -1080,7 +1070,7 @@ void GPIOBUS::MakeTable(void)
|
|||
|
||||
int i;
|
||||
int j;
|
||||
BOOL tblParity[256];
|
||||
bool tblParity[256];
|
||||
#if SIGNAL_CONTROL_MODE == 0
|
||||
int index;
|
||||
int shift;
|
||||
|
@ -1249,13 +1239,13 @@ void GPIOBUS::SetSignal(int pin, bool ast)
|
|||
// Wait for signal change
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool GPIOBUS::WaitSignal(int pin, BOOL ast)
|
||||
bool GPIOBUS::WaitSignal(int pin, int ast)
|
||||
{
|
||||
// Get current time
|
||||
DWORD now = SysTimer::GetTimerLow();
|
||||
uint32_t now = SysTimer::GetTimerLow();
|
||||
|
||||
// Calculate timeout (3000ms)
|
||||
DWORD timeout = 3000 * 1000;
|
||||
uint32_t timeout = 3000 * 1000;
|
||||
|
||||
// end immediately if the signal has changed
|
||||
do {
|
||||
|
@ -1416,15 +1406,15 @@ BUS::phase_t GPIOBUS::GetPhaseRaw(DWORD raw_data)
|
|||
if (GetPinRaw(raw_data, PIN_SEL))
|
||||
{
|
||||
if(GetPinRaw(raw_data, PIN_IO)){
|
||||
return BUS::reselection;
|
||||
return BUS::phase_t::reselection;
|
||||
}else{
|
||||
return BUS::selection;
|
||||
return BUS::phase_t::selection;
|
||||
}
|
||||
}
|
||||
|
||||
// Bus busy phase
|
||||
if (!GetPinRaw(raw_data, PIN_BSY)) {
|
||||
return BUS::busfree;
|
||||
return BUS::phase_t::busfree;
|
||||
}
|
||||
|
||||
// Get target phase from bus signal line
|
||||
|
|
|
@ -308,7 +308,7 @@ public:
|
|||
GPIOBUS()= default;
|
||||
~GPIOBUS() final = default;
|
||||
// Destructor
|
||||
bool Init(mode_e mode = TARGET) override;
|
||||
bool Init(mode_e mode = mode_e::TARGET) override;
|
||||
// Initialization
|
||||
void Reset() override;
|
||||
// Reset
|
||||
|
@ -320,7 +320,7 @@ public:
|
|||
// Bus signal acquisition
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
inline DWORD Acquire() override
|
||||
inline uint32_t Acquire() override
|
||||
{
|
||||
#if defined(__x86_64__) || defined(__X86__)
|
||||
// Only used for development/debugging purposes. Isn't really applicable
|
||||
|
@ -429,7 +429,7 @@ private:
|
|||
// Get SCSI input signal value
|
||||
void SetSignal(int pin, bool ast) override;
|
||||
// Set SCSI output signal value
|
||||
bool WaitSignal(int pin, BOOL ast);
|
||||
bool WaitSignal(int pin, int ast);
|
||||
// Wait for a signal to change
|
||||
// Interrupt control
|
||||
void DisableIRQ();
|
||||
|
@ -448,7 +448,7 @@ private:
|
|||
// Set GPIO drive strength
|
||||
|
||||
|
||||
mode_e actmode = TARGET; // Operation mode
|
||||
mode_e actmode = mode_e::TARGET; // Operation mode
|
||||
|
||||
uint32_t baseaddr = 0; // Base address
|
||||
|
||||
|
|
|
@ -25,14 +25,14 @@
|
|||
// System timer address
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
volatile DWORD* SysTimer::systaddr;
|
||||
volatile uint32_t* SysTimer::systaddr;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// ARM timer address
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
volatile DWORD* SysTimer::armtaddr;
|
||||
volatile uint32_t* SysTimer::armtaddr;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
|
@ -46,7 +46,7 @@ volatile DWORD SysTimer::corefreq;
|
|||
// Initialize the system timer
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SysTimer::Init(DWORD *syst, DWORD *armt)
|
||||
void SysTimer::Init(uint32_t *syst, uint32_t *armt)
|
||||
{
|
||||
// RPI Mailbox property interface
|
||||
// Get max clock rate
|
||||
|
@ -59,7 +59,7 @@ void SysTimer::Init(DWORD *syst, DWORD *armt)
|
|||
//
|
||||
// Clock id
|
||||
// 0x000000004: CORE
|
||||
DWORD maxclock[32] = { 32, 0, 0x00030004, 8, 0, 4, 0, 0 };
|
||||
uint32_t maxclock[32] = { 32, 0, 0x00030004, 8, 0, 4, 0, 0 };
|
||||
|
||||
// Save the base address
|
||||
systaddr = syst;
|
||||
|
@ -83,7 +83,7 @@ void SysTimer::Init(DWORD *syst, DWORD *armt)
|
|||
// Get system timer low byte
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
DWORD SysTimer::GetTimerLow() {
|
||||
uint32_t SysTimer::GetTimerLow() {
|
||||
return systaddr[SYST_CLO];
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ DWORD SysTimer::GetTimerLow() {
|
|||
// Get system timer high byte
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
DWORD SysTimer::GetTimerHigh() {
|
||||
uint32_t SysTimer::GetTimerHigh() {
|
||||
return systaddr[SYST_CHI];
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,7 @@ void SysTimer::SleepNsec(DWORD nsec)
|
|||
}
|
||||
|
||||
// Calculate the timer difference
|
||||
DWORD diff = corefreq * nsec / 1000;
|
||||
uint32_t diff = corefreq * nsec / 1000;
|
||||
|
||||
// Return if the difference in time is too small
|
||||
if (diff == 0) {
|
||||
|
@ -117,7 +117,7 @@ void SysTimer::SleepNsec(DWORD nsec)
|
|||
}
|
||||
|
||||
// Start
|
||||
DWORD start = armtaddr[ARMT_FREERUN];
|
||||
uint32_t start = armtaddr[ARMT_FREERUN];
|
||||
|
||||
// Loop until timer has elapsed
|
||||
while ((armtaddr[ARMT_FREERUN] - start) < diff);
|
||||
|
@ -135,6 +135,6 @@ void SysTimer::SleepUsec(DWORD usec)
|
|||
return;
|
||||
}
|
||||
|
||||
DWORD now = GetTimerLow();
|
||||
uint32_t now = GetTimerLow();
|
||||
while ((GetTimerLow() - now) < usec);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2021 Uwe Seimet
|
||||
// Copyright (C) 2021-2022 Uwe Seimet
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
@ -43,11 +43,15 @@ Localizer::Localizer()
|
|||
Add(ERROR_MISSING_FILENAME, "sv", "Filnamn saknas");
|
||||
Add(ERROR_MISSING_FILENAME, "fr", "Nom de fichier manquant");
|
||||
Add(ERROR_MISSING_FILENAME, "es", "Falta el nombre del archivo");
|
||||
Add(ERROR_DEVICE_MISSING_FILENAME, "en", "Device type %1 requires a filename");
|
||||
Add(ERROR_DEVICE_MISSING_FILENAME, "de", "Gerätetyp %1 erfordert einen Dateinamen");
|
||||
Add(ERROR_IMAGE_IN_USE, "en", "Image file '%1' is already being used by ID %2, unit %3");
|
||||
Add(ERROR_IMAGE_IN_USE, "de", "Image-Datei '%1' wird bereits von ID %2, Einheit %3 benutzt");
|
||||
Add(ERROR_IMAGE_IN_USE, "sv", "Skivbildfilen '%1' används redan av ID %2, LUN %3");
|
||||
Add(ERROR_IMAGE_IN_USE, "fr", "Le fichier d'image '%1' est déjà utilisé par l'ID %2, unité %3");
|
||||
Add(ERROR_IMAGE_IN_USE, "es", "El archivo de imagen '%1' ya está siendo utilizado por el ID %2, unidad %3");
|
||||
Add(ERROR_IMAGE_FILE_INFO, "en", "Can't create image file info for '%1'");
|
||||
Add(ERROR_IMAGE_FILE_INFO, "de", "Image-Datei-Information für '%1' kann nicht erzeugt werden");
|
||||
Add(ERROR_RESERVED_ID, "en", "Device ID %1 is reserved");
|
||||
Add(ERROR_RESERVED_ID, "de", "Geräte-ID %1 ist reserviert");
|
||||
Add(ERROR_RESERVED_ID, "sv", "Enhets-ID %1 är reserverat");
|
||||
|
@ -78,6 +82,8 @@ Localizer::Localizer()
|
|||
Add(ERROR_DUPLICATE_ID, "sv", "Duplikat ID %1, LUN %2");
|
||||
Add(ERROR_DUPLICATE_ID, "fr", "ID %1, unité %2 dupliquée");
|
||||
Add(ERROR_DUPLICATE_ID, "es", "ID duplicado %1, unidad %2");
|
||||
Add(ERROR_DETACH, "en", "Couldn't detach device");
|
||||
Add(ERROR_DETACH, "de", "Geräte konnte nicht entfernt werden");
|
||||
Add(ERROR_EJECT_REQUIRED, "en", "Existing medium must first be ejected");
|
||||
Add(ERROR_EJECT_REQUIRED, "de", "Das vorhandene Medium muss erst ausgeworfen werden");
|
||||
Add(ERROR_EJECT_REQUIRED, "sv", "Nuvarande skiva måste utmatas först");
|
||||
|
@ -118,6 +124,24 @@ Localizer::Localizer()
|
|||
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "sv", "Enhetstypen %1 kan inte använda andra blockstorlekar");
|
||||
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "fr", "Taille de block pour le type de périphérique %1 non configurable");
|
||||
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "es", "El tamaño del bloque para el tipo de dispositivo %1 no es configurable");
|
||||
Add(ERROR_SCSI_CONTROLLER, "en", "Couldn't create SCSI controller");
|
||||
Add(ERROR_SCSI_CONTROLLER, "de", "SCSI-Controller konnte nicht erzeugt werden");
|
||||
Add(ERROR_INVALID_ID, "en", "Invalid device ID %1 (0-%2)");
|
||||
Add(ERROR_INVALID_ID, "de", "Ungültige Geräte-ID %1 (0-%2)");
|
||||
Add(ERROR_INVALID_LUN, "en", "Invalid LUN %1 (0-%2)");
|
||||
Add(ERROR_INVALID_LUN, "de", "Ungültige LUN %1 (0-%2)");
|
||||
Add(ERROR_LUN0, "en", "LUN 0 cannot be detached as long as there is still another LUN");
|
||||
Add(ERROR_LUN0, "de", "LUN 0 kann nicht entfernt werden, solange noch eine andere LUN existiert");
|
||||
Add(ERROR_INITIALIZATION, "en", "Initialization of %1 device, ID %2, LUN %3 failed");
|
||||
Add(ERROR_INITIALIZATION, "de", "Initialisierung von %1-Gerät, ID %2, LUN %3 fehlgeschlagen");
|
||||
Add(ERROR_OPERATION_DENIED_STOPPABLE, "en", "%1 operation denied, %2 isn't stoppable'");
|
||||
Add(ERROR_OPERATION_DENIED_STOPPABLE, "de", "%1-Operation verweigert, %2 ist nicht stopbar'");
|
||||
Add(ERROR_OPERATION_DENIED_REMOVABLE, "en", "%1 operation denied, %2 isn't removable'");
|
||||
Add(ERROR_OPERATION_DENIED_REMOVABLE, "de", "%1-Operation verweigert, %2 ist nicht wechselbar'");
|
||||
Add(ERROR_OPERATION_DENIED_PROTECTABLE, "en", "%1 operation denied, %2 isn't protectable'");
|
||||
Add(ERROR_OPERATION_DENIED_PROTECTABLE, "de", "%1-Operation verweigert, %2 ist nicht schützbar'");
|
||||
Add(ERROR_OPERATION_DENIED_READY, "en", "%1 operation denied, %2 isn't ready'");
|
||||
Add(ERROR_OPERATION_DENIED_READY, "de", "%1-Operation verweigert, %2 ist nicht bereit'");
|
||||
}
|
||||
|
||||
void Localizer::Add(LocalizationKey key, const string& locale, string_view value)
|
||||
|
@ -132,29 +156,31 @@ void Localizer::Add(LocalizationKey key, const string& locale, string_view value
|
|||
}
|
||||
|
||||
string Localizer::Localize(LocalizationKey key, const string& locale, const string& arg1, const string& arg2,
|
||||
const string &arg3)
|
||||
const string &arg3) const
|
||||
{
|
||||
string locale_lower = locale;
|
||||
transform(locale_lower.begin(), locale_lower.end(), locale_lower.begin(), ::tolower);
|
||||
|
||||
unordered_map<LocalizationKey, string> messages = localized_messages[locale_lower];
|
||||
if (messages.empty()) {
|
||||
auto it = localized_messages.find(locale_lower);
|
||||
if (it == localized_messages.end()) {
|
||||
// Try to fall back to country-indepedent locale (e.g. "en" instead of "en_US")
|
||||
if (locale_lower.length() > 2) {
|
||||
messages = localized_messages[locale_lower.substr(0, 2)];
|
||||
it = localized_messages.find(locale_lower.substr(0, 2));
|
||||
}
|
||||
if (messages.empty()) {
|
||||
messages = localized_messages["en"];
|
||||
if (it == localized_messages.end()) {
|
||||
it = localized_messages.find("en");
|
||||
}
|
||||
}
|
||||
|
||||
assert(!messages.empty());
|
||||
assert(it != localized_messages.end());
|
||||
|
||||
string message = messages[key];
|
||||
auto messages = it->second;
|
||||
if (messages.empty()) {
|
||||
return "Missing localization for enum value " + to_string(key);
|
||||
}
|
||||
|
||||
string message = messages[key];
|
||||
|
||||
message = regex_replace(message, regex("%1"), arg1);
|
||||
message = regex_replace(message, regex("%2"), arg2);
|
||||
message = regex_replace(message, regex("%3"), arg3);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2021 Uwe Seimet
|
||||
// Copyright (C) 2021-2022 Uwe Seimet
|
||||
//
|
||||
// Message localization support. Currently only for messages with up to 3 string parameters.
|
||||
//
|
||||
|
@ -23,13 +23,16 @@ enum LocalizationKey {
|
|||
ERROR_LOG_LEVEL,
|
||||
ERROR_MISSING_DEVICE_ID,
|
||||
ERROR_MISSING_FILENAME,
|
||||
ERROR_DEVICE_MISSING_FILENAME,
|
||||
ERROR_IMAGE_IN_USE,
|
||||
ERROR_IMAGE_FILE_INFO,
|
||||
ERROR_RESERVED_ID,
|
||||
ERROR_NON_EXISTING_DEVICE,
|
||||
ERROR_NON_EXISTING_UNIT,
|
||||
ERROR_UNKNOWN_DEVICE_TYPE,
|
||||
ERROR_MISSING_DEVICE_TYPE,
|
||||
ERROR_DUPLICATE_ID,
|
||||
ERROR_DETACH,
|
||||
ERROR_EJECT_REQUIRED,
|
||||
ERROR_DEVICE_NAME_UPDATE,
|
||||
ERROR_SHUTDOWN_MODE_MISSING,
|
||||
|
@ -37,7 +40,16 @@ enum LocalizationKey {
|
|||
ERROR_SHUTDOWN_PERMISSION,
|
||||
ERROR_FILE_OPEN,
|
||||
ERROR_BLOCK_SIZE,
|
||||
ERROR_BLOCK_SIZE_NOT_CONFIGURABLE
|
||||
ERROR_BLOCK_SIZE_NOT_CONFIGURABLE,
|
||||
ERROR_SCSI_CONTROLLER,
|
||||
ERROR_INVALID_ID,
|
||||
ERROR_INVALID_LUN,
|
||||
ERROR_LUN0,
|
||||
ERROR_INITIALIZATION,
|
||||
ERROR_OPERATION_DENIED_STOPPABLE,
|
||||
ERROR_OPERATION_DENIED_REMOVABLE,
|
||||
ERROR_OPERATION_DENIED_PROTECTABLE,
|
||||
ERROR_OPERATION_DENIED_READY
|
||||
};
|
||||
|
||||
class Localizer
|
||||
|
@ -47,7 +59,7 @@ public:
|
|||
Localizer();
|
||||
~Localizer() = default;
|
||||
|
||||
string Localize(LocalizationKey, const string&, const string& = "", const string& = "", const string& = "");
|
||||
string Localize(LocalizationKey, const string&, const string& = "", const string& = "", const string& = "") const;
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -22,13 +22,13 @@ BUS::phase_t GetPhase(const data_capture *sample)
|
|||
// Selection Phase
|
||||
if (GetSel(sample))
|
||||
{
|
||||
return BUS::selection;
|
||||
return BUS::phase_t::selection;
|
||||
}
|
||||
|
||||
// Bus busy phase
|
||||
if (!GetBsy(sample))
|
||||
{
|
||||
return BUS::busfree;
|
||||
return BUS::phase_t::busfree;
|
||||
}
|
||||
|
||||
// Get target phase from bus signal line
|
||||
|
|
|
@ -104,7 +104,7 @@ static void print_html_data(ofstream& html_fp, const data_capture *data_capture_
|
|||
bool prev_data_valid = false;
|
||||
bool curr_data_valid;
|
||||
DWORD selected_id = 0;
|
||||
BUS::phase_t prev_phase = BUS::busfree;
|
||||
BUS::phase_t prev_phase = BUS::phase_t::busfree;
|
||||
bool close_row = false;
|
||||
int data_space_count = 0;
|
||||
bool collapsible_div_active = false;
|
||||
|
@ -117,7 +117,7 @@ static void print_html_data(ofstream& html_fp, const data_capture *data_capture_
|
|||
data = &data_capture_array[idx];
|
||||
curr_data_valid = GetAck(data) && GetReq(data);
|
||||
BUS::phase_t phase = GetPhase(data);
|
||||
if (phase == BUS::selection && !GetBsy(data))
|
||||
if (phase == BUS::phase_t::selection && !GetBsy(data))
|
||||
{
|
||||
selected_id = GetData(data);
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ static BYTE prev_value[32] = {0xFF};
|
|||
|
||||
extern double ns_per_loop;
|
||||
|
||||
static BOOL get_pin_value(DWORD data, int pin)
|
||||
static BYTE get_pin_value(DWORD data, int pin)
|
||||
{
|
||||
return (data >> pin) & 1;
|
||||
}
|
||||
|
@ -77,16 +77,16 @@ static BYTE get_data_field(DWORD data)
|
|||
static void vcd_output_if_changed_phase(ofstream& fp, DWORD data, int pin, char symbol)
|
||||
{
|
||||
BUS::phase_t new_value = GPIOBUS::GetPhaseRaw(data);
|
||||
if (prev_value[pin] != new_value)
|
||||
if (prev_value[pin] != (int)new_value)
|
||||
{
|
||||
prev_value[pin] = new_value;
|
||||
prev_value[pin] = (int)new_value;
|
||||
fp << "s" << GPIOBUS::GetPhaseStrRaw(new_value) << " " << symbol << endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void vcd_output_if_changed_bool(ofstream& fp, DWORD data, int pin, char symbol)
|
||||
{
|
||||
BOOL new_value = get_pin_value(data, pin);
|
||||
BYTE new_value = get_pin_value(data, pin);
|
||||
if (prev_value[pin] != new_value)
|
||||
{
|
||||
prev_value[pin] = new_value;
|
||||
|
|
|
@ -85,9 +85,8 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
using BYTE = unsigned char;
|
||||
using WORD =uint16_t;
|
||||
using WORD = uint16_t;
|
||||
using DWORD = uint32_t;
|
||||
using BOOL = int;
|
||||
using TCHAR = char;
|
||||
|
||||
#if !defined(FALSE)
|
||||
|
|
|
@ -23,7 +23,7 @@ using namespace rascsi_interface;
|
|||
static const char COMPONENT_SEPARATOR = ':';
|
||||
static const char KEY_VALUE_SEPARATOR = '=';
|
||||
|
||||
Localizer localizer;
|
||||
const Localizer localizer;
|
||||
|
||||
void protobuf_util::ParseParameters(PbDeviceDefinition& device, const string& params)
|
||||
{
|
||||
|
@ -114,33 +114,32 @@ void protobuf_util::SerializeMessage(int fd, const google::protobuf::Message& me
|
|||
void protobuf_util::DeserializeMessage(int fd, google::protobuf::Message& message)
|
||||
{
|
||||
// Read the header with the size of the protobuf data
|
||||
uint8_t header_buf[4];
|
||||
size_t bytes_read = ReadNBytes(fd, header_buf, sizeof(header_buf));
|
||||
if (bytes_read < sizeof(header_buf)) {
|
||||
vector<byte> header_buf(4);
|
||||
if (ReadBytes(fd, header_buf) < header_buf.size()) {
|
||||
return;
|
||||
}
|
||||
size_t size = (header_buf[3] << 24) + (header_buf[2] << 16) + (header_buf[1] << 8) + header_buf[0];
|
||||
|
||||
size_t size = ((int)header_buf[3] << 24) + ((int)header_buf[2] << 16) + ((int)header_buf[1] << 8) + (int)header_buf[0];
|
||||
if (size <= 0) {
|
||||
throw io_exception("Broken protobuf message header");
|
||||
throw io_exception("Invalid protobuf message header");
|
||||
}
|
||||
|
||||
// Read the binary protobuf data
|
||||
auto data_buf = make_unique<uint8_t[]>(size);
|
||||
bytes_read = ReadNBytes(fd, data_buf.get(), size);
|
||||
if (bytes_read < size) {
|
||||
vector<byte> data_buf(size);
|
||||
if (ReadBytes(fd, data_buf) < data_buf.size()) {
|
||||
throw io_exception("Missing protobuf message data");
|
||||
}
|
||||
|
||||
// Create protobuf message
|
||||
string data((const char *)data_buf.get(), size);
|
||||
string data((const char *)data_buf.data(), size);
|
||||
message.ParseFromString(data);
|
||||
}
|
||||
|
||||
size_t protobuf_util::ReadNBytes(int fd, uint8_t *buf, size_t n)
|
||||
size_t protobuf_util::ReadBytes(int fd, vector<byte>& buf)
|
||||
{
|
||||
size_t offset = 0;
|
||||
while (offset < n) {
|
||||
ssize_t len = read(fd, buf + offset, n - offset);
|
||||
while (offset < buf.size()) {
|
||||
ssize_t len = read(fd, &buf[offset], buf.size() - offset);
|
||||
if (len <= 0) {
|
||||
return len;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace protobuf_util
|
|||
void AddParam(PbDeviceDefinition&, const string&, string_view);
|
||||
void SerializeMessage(int, const google::protobuf::Message&);
|
||||
void DeserializeMessage(int, google::protobuf::Message&);
|
||||
size_t ReadNBytes(int, uint8_t *, size_t);
|
||||
size_t ReadBytes(int, vector<byte>&);
|
||||
bool ReturnLocalizedError(const CommandContext&, const LocalizationKey, const string& = "", const string& = "",
|
||||
const string& = "");
|
||||
bool ReturnLocalizedError(const CommandContext&, const LocalizationKey, const PbErrorCode, const string& = "",
|
||||
|
|
|
@ -66,7 +66,7 @@ string current_log_level; // Some versions of spdlog do not support get_log_le
|
|||
string access_token;
|
||||
unordered_set<int> reserved_ids;
|
||||
DeviceFactory& device_factory = DeviceFactory::instance();
|
||||
ControllerManager&controller_manager = ControllerManager::instance();
|
||||
ControllerManager controller_manager;
|
||||
RascsiImage rascsi_image;
|
||||
RascsiResponse rascsi_response(&device_factory, &rascsi_image);
|
||||
void DetachAll();
|
||||
|
@ -91,7 +91,7 @@ void Banner(int argc, char* argv[])
|
|||
{
|
||||
FPRT(stdout,"SCSI Target Emulator RaSCSI Reloaded ");
|
||||
FPRT(stdout,"version %s (%s, %s)\n",
|
||||
rascsi_get_version_string(),
|
||||
rascsi_get_version_string().c_str(),
|
||||
__DATE__,
|
||||
__TIME__);
|
||||
FPRT(stdout,"Powered by XM6 TypeG Technology / ");
|
||||
|
@ -370,7 +370,7 @@ string SetReservedIds(string_view ids)
|
|||
void DetachAll()
|
||||
{
|
||||
controller_manager.DeleteAllControllers();
|
||||
DeviceFactory::instance().DeleteAllDevices();
|
||||
device_factory.DeleteAllDevices();
|
||||
FileSupport::UnreserveAll();
|
||||
|
||||
LOGINFO("Detached all devices")
|
||||
|
@ -387,8 +387,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
|
|||
}
|
||||
|
||||
if (unit >= AbstractController::LUN_MAX) {
|
||||
return ReturnStatus(context, false, "Invalid unit " + to_string(unit) + " (0-" + to_string(AbstractController::LUN_MAX)
|
||||
+ ")");
|
||||
return ReturnLocalizedError(context, ERROR_INVALID_LUN, to_string(unit), to_string(AbstractController::LUN_MAX));
|
||||
}
|
||||
|
||||
string filename = GetParam(pb_device, "file");
|
||||
|
@ -449,7 +448,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
|
|||
if (file_support != nullptr && !device->IsRemovable() && filename.empty()) {
|
||||
device_factory.DeleteDevice(device);
|
||||
|
||||
return ReturnStatus(context, false, "Device type " + PbDeviceType_Name(type) + " requires a filename");
|
||||
return ReturnLocalizedError(context, ERROR_MISSING_FILENAME, PbDeviceType_Name(type));
|
||||
}
|
||||
|
||||
Filepath filepath;
|
||||
|
@ -511,8 +510,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
|
|||
if (!device->Init(params)) {
|
||||
device_factory.DeleteDevice(device);
|
||||
|
||||
return ReturnStatus(context, false, "Initialization of " + PbDeviceType_Name(type) + " device, ID " +to_string(id) +
|
||||
", unit " +to_string(unit) + " failed");
|
||||
return ReturnLocalizedError(context, ERROR_INITIALIZATION, PbDeviceType_Name(type), to_string(id), to_string(unit));
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&ctrl_mutex);
|
||||
|
@ -520,7 +518,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
|
|||
if (!controller_manager.CreateScsiController(bus, device)) {
|
||||
pthread_mutex_unlock(&ctrl_mutex);
|
||||
|
||||
return ReturnStatus(context, false, "Couldn't create SCSI controller instance");
|
||||
return ReturnLocalizedError(context, ERROR_SCSI_CONTROLLER);
|
||||
}
|
||||
pthread_mutex_unlock(&ctrl_mutex);
|
||||
|
||||
|
@ -543,7 +541,7 @@ bool Detach(const CommandContext& context, PrimaryDevice *device, bool dryRun)
|
|||
for (const Device *d : device_factory.GetAllDevices()) {
|
||||
// LUN 0 can only be detached if there is no other LUN anymore
|
||||
if (d->GetId() == device->GetId() && d->GetLun()) {
|
||||
return ReturnStatus(context, false, "LUN 0 cannot be detached as long as there is still another LUN");
|
||||
return ReturnLocalizedError(context, ERROR_LUN0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -563,7 +561,7 @@ bool Detach(const CommandContext& context, PrimaryDevice *device, bool dryRun)
|
|||
if (!controller_manager.FindController(id)->DeleteDevice(device)) {
|
||||
pthread_mutex_unlock(&ctrl_mutex);
|
||||
|
||||
return ReturnStatus(context, false, "Couldn't detach device");
|
||||
return ReturnLocalizedError(context, ERROR_DETACH);
|
||||
}
|
||||
device_factory.DeleteDevice(device);
|
||||
pthread_mutex_unlock(&ctrl_mutex);
|
||||
|
@ -716,8 +714,7 @@ bool ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_devi
|
|||
return ReturnLocalizedError(context, ERROR_MISSING_DEVICE_ID);
|
||||
}
|
||||
if (id >= ControllerManager::DEVICE_MAX) {
|
||||
return ReturnStatus(context, false, "Invalid device ID " + to_string(id) + " (0-"
|
||||
+ to_string(ControllerManager::DEVICE_MAX - 1) + ")");
|
||||
return ReturnLocalizedError(context, ERROR_INVALID_ID, to_string(id), to_string(ControllerManager::DEVICE_MAX - 1));
|
||||
}
|
||||
|
||||
if (operation == ATTACH && reserved_ids.find(id) != reserved_ids.end()) {
|
||||
|
@ -726,7 +723,7 @@ bool ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_devi
|
|||
|
||||
// Check the Unit Number
|
||||
if (unit < 0 || unit >= AbstractController::LUN_MAX) {
|
||||
return ReturnStatus(context, false, "Invalid unit " + to_string(unit) + " (0-" + to_string(AbstractController::LUN_MAX - 1) + ")");
|
||||
return ReturnLocalizedError(context, ERROR_INVALID_LUN, to_string(unit), to_string(AbstractController::LUN_MAX - 1));
|
||||
}
|
||||
|
||||
if (operation == ATTACH) {
|
||||
|
@ -749,18 +746,18 @@ bool ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_devi
|
|||
}
|
||||
|
||||
if ((operation == START || operation == STOP) && !device->IsStoppable()) {
|
||||
return ReturnStatus(context, false, PbOperation_Name(operation) + " operation denied (" + device->GetType() + " isn't stoppable)");
|
||||
return ReturnLocalizedError(context, ERROR_OPERATION_DENIED_STOPPABLE, device->GetType());
|
||||
}
|
||||
|
||||
if ((operation == INSERT || operation == EJECT) && !device->IsRemovable()) {
|
||||
return ReturnStatus(context, false, PbOperation_Name(operation) + " operation denied (" + device->GetType() + " isn't removable)");
|
||||
return ReturnLocalizedError(context, ERROR_OPERATION_DENIED_REMOVABLE, device->GetType());
|
||||
}
|
||||
|
||||
if ((operation == PROTECT || operation == UNPROTECT) && !device->IsProtectable()) {
|
||||
return ReturnStatus(context, false, PbOperation_Name(operation) + " operation denied (" + device->GetType() + " isn't protectable)");
|
||||
return ReturnLocalizedError(context, ERROR_OPERATION_DENIED_PROTECTABLE, device->GetType());
|
||||
}
|
||||
if ((operation == PROTECT || operation == UNPROTECT) && !device->IsReady()) {
|
||||
return ReturnStatus(context, false, PbOperation_Name(operation) + " operation denied (" + device->GetType() + " isn't ready)");
|
||||
return ReturnLocalizedError(context, ERROR_OPERATION_DENIED_READY, device->GetType());
|
||||
}
|
||||
|
||||
switch (operation) {
|
||||
|
@ -991,8 +988,8 @@ bool ParseArgument(int argc, char* argv[], int& port)
|
|||
string name;
|
||||
string log_level;
|
||||
|
||||
string locale = setlocale(LC_MESSAGES, "");
|
||||
if (locale == "C") {
|
||||
const char *locale = setlocale(LC_MESSAGES, "");
|
||||
if (locale == nullptr || !strcmp(locale, "C")) {
|
||||
locale = "en";
|
||||
}
|
||||
|
||||
|
@ -1211,12 +1208,12 @@ static void *MonThread(void *) //NOSONAR The pointer cannot be const void * beca
|
|||
}
|
||||
|
||||
// Read magic string
|
||||
char magic[6];
|
||||
int bytes_read = ReadNBytes(context.fd, (uint8_t *)magic, sizeof(magic));
|
||||
vector<byte> magic(6);
|
||||
size_t bytes_read = ReadBytes(context.fd, magic);
|
||||
if (!bytes_read) {
|
||||
continue;
|
||||
}
|
||||
if (bytes_read != sizeof(magic) || strncmp(magic, "RASCSI", sizeof(magic))) {
|
||||
if (bytes_read != magic.size() || memcmp(magic.data(), "RASCSI", magic.size())) {
|
||||
throw io_exception("Invalid magic");
|
||||
}
|
||||
|
||||
|
@ -1320,7 +1317,7 @@ static void *MonThread(void *) //NOSONAR The pointer cannot be const void * beca
|
|||
SerializeMessage(context.fd, result);
|
||||
}
|
||||
else {
|
||||
ReturnStatus(context, false, "Can't get image file info for '" + filename + "'");
|
||||
ReturnLocalizedError(context, ERROR_IMAGE_FILE_INFO);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1390,14 +1387,6 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Get temporary operation info, in order to trigger an assertion on startup if the operation list is incomplete
|
||||
// TODO Move to unit test?
|
||||
PbResult pb_operation_info_result;
|
||||
const auto operation_info = unique_ptr<PbOperationInfo>(rascsi_response.GetOperationInfo(pb_operation_info_result, 0));
|
||||
assert(operation_info->operations_size() == PbOperation_ARRAYSIZE - 1);
|
||||
#endif
|
||||
|
||||
BUS::phase_t phase;
|
||||
|
||||
// added setvbuf to override stdout buffering, so logs are written immediately and not when the process exits.
|
||||
|
@ -1463,7 +1452,7 @@ int main(int argc, char* argv[])
|
|||
// Main Loop
|
||||
while (running) {
|
||||
// Work initialization
|
||||
phase = BUS::busfree;
|
||||
phase = BUS::phase_t::busfree;
|
||||
|
||||
#ifdef USE_SEL_EVENT_ENABLE
|
||||
// SEL signal polling
|
||||
|
@ -1489,7 +1478,7 @@ int main(int argc, char* argv[])
|
|||
// Wait until BSY is released as there is a possibility for the
|
||||
// initiator to assert it while setting the ID (for up to 3 seconds)
|
||||
if (bus->GetBSY()) {
|
||||
int now = SysTimer::GetTimerLow();
|
||||
uint32_t now = SysTimer::GetTimerLow();
|
||||
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) {
|
||||
bus->Acquire();
|
||||
if (!bus->GetBSY()) {
|
||||
|
@ -1515,13 +1504,13 @@ int main(int argc, char* argv[])
|
|||
if (controller != nullptr) {
|
||||
initiator_id = controller->ExtractInitiatorId(id_data);
|
||||
|
||||
if (controller->Process(initiator_id) == BUS::selection) {
|
||||
phase = BUS::selection;
|
||||
if (controller->Process(initiator_id) == BUS::phase_t::selection) {
|
||||
phase = BUS::phase_t::selection;
|
||||
}
|
||||
}
|
||||
|
||||
// Return to bus monitoring if the selection phase has not started
|
||||
if (phase != BUS::selection) {
|
||||
if (phase != BUS::phase_t::selection) {
|
||||
pthread_mutex_unlock(&ctrl_mutex);
|
||||
continue;
|
||||
}
|
||||
|
@ -1541,7 +1530,7 @@ int main(int argc, char* argv[])
|
|||
phase = controller->Process(initiator_id);
|
||||
|
||||
// End when the bus is free
|
||||
if (phase == BUS::busfree) {
|
||||
if (phase == BUS::phase_t::busfree) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,6 @@
|
|||
using namespace rascsi_interface;
|
||||
using namespace protobuf_util;
|
||||
|
||||
list<string> RascsiResponse::log_levels = { "trace", "debug", "info", "warn", "err", "critical", "off" };
|
||||
|
||||
|
||||
PbDeviceProperties *RascsiResponse::GetDeviceProperties(const Device *device)
|
||||
{
|
||||
auto properties = make_unique<PbDeviceProperties>().release();
|
||||
|
@ -350,164 +347,135 @@ PbMappingInfo *RascsiResponse::GetMappingInfo(PbResult& result)
|
|||
|
||||
PbOperationInfo *RascsiResponse::GetOperationInfo(PbResult& result, int depth)
|
||||
{
|
||||
auto operation_info = make_unique<PbOperationInfo>().release();
|
||||
auto operation_info = make_unique<PbOperationInfo>();
|
||||
|
||||
auto meta_data = make_unique<PbOperationMetaData>();
|
||||
AddOperationParameter(meta_data.get(), "name", "Image file name in case of a mass storage device");
|
||||
AddOperationParameter(meta_data.get(), "interface", "Comma-separated prioritized network interface list");
|
||||
AddOperationParameter(meta_data.get(), "inet", "IP address and netmask of the network bridge");
|
||||
AddOperationParameter(meta_data.get(), "cmd", "Print command for the printer device");
|
||||
AddOperationParameter(meta_data.get(), "timeout", "Reservation timeout for the printer device in seconds");
|
||||
CreateOperation(operation_info, meta_data.get(), ATTACH, "Attach device, device-specific parameters are required");
|
||||
auto operation = CreateOperation(*operation_info, ATTACH, "Attach device, device-specific parameters are required");
|
||||
AddOperationParameter(*operation, "name", "Image file name in case of a mass storage device");
|
||||
AddOperationParameter(*operation, "interface", "Comma-separated prioritized network interface list");
|
||||
AddOperationParameter(*operation, "inet", "IP address and netmask of the network bridge");
|
||||
AddOperationParameter(*operation, "cmd", "Print command for the printer device");
|
||||
AddOperationParameter(*operation, "timeout", "Reservation timeout for the printer device in seconds");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
CreateOperation(operation_info, meta_data.get(), DETACH, "Detach device, device-specific parameters are required");
|
||||
CreateOperation(*operation_info, DETACH, "Detach device, device-specific parameters are required");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
CreateOperation(operation_info, meta_data.get(), DETACH_ALL, "Detach all devices");
|
||||
CreateOperation(*operation_info, DETACH_ALL, "Detach all devices");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
CreateOperation(operation_info, meta_data.get(), START, "Start device, device-specific parameters are required");
|
||||
CreateOperation(*operation_info, START, "Start device, device-specific parameters are required");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
CreateOperation(operation_info, meta_data.get(), STOP, "Stop device, device-specific parameters are required");
|
||||
CreateOperation(*operation_info, STOP, "Stop device, device-specific parameters are required");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
AddOperationParameter(meta_data.get(), "file", "Image file name", "", true);
|
||||
CreateOperation(operation_info, meta_data.get(), INSERT, "Insert medium, device-specific parameters are required");
|
||||
operation = CreateOperation(*operation_info, INSERT, "Insert medium, device-specific parameters are required");
|
||||
AddOperationParameter(*operation, "file", "Image file name", "", true);
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
CreateOperation(operation_info, meta_data.get(), EJECT, "Eject medium, device-specific parameters are required");
|
||||
CreateOperation(*operation_info, EJECT, "Eject medium, device-specific parameters are required");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
CreateOperation(operation_info, meta_data.get(), PROTECT, "Protect medium, device-specific parameters are required");
|
||||
CreateOperation(*operation_info, PROTECT, "Protect medium, device-specific parameters are required");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
CreateOperation(operation_info, meta_data.get(), UNPROTECT, "Unprotect medium, device-specific parameters are required");
|
||||
CreateOperation(*operation_info, UNPROTECT, "Unprotect medium, device-specific parameters are required");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
operation = CreateOperation(*operation_info, SERVER_INFO, "Get rascsi server information");
|
||||
if (depth) {
|
||||
AddOperationParameter(meta_data.get(), "folder_pattern", "Pattern for filtering image folder names");
|
||||
AddOperationParameter(*operation, "folder_pattern", "Pattern for filtering image folder names");
|
||||
}
|
||||
AddOperationParameter(meta_data.get(), "file_pattern", "Pattern for filtering image file names");
|
||||
CreateOperation(operation_info, meta_data.get(), SERVER_INFO, "Get rascsi server information");
|
||||
AddOperationParameter(*operation, "file_pattern", "Pattern for filtering image file names");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
CreateOperation(operation_info, meta_data.get(), VERSION_INFO, "Get rascsi server version");
|
||||
CreateOperation(*operation_info, VERSION_INFO, "Get rascsi server version");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
CreateOperation(operation_info, meta_data.get(), DEVICES_INFO, "Get information on attached devices");
|
||||
CreateOperation(*operation_info, DEVICES_INFO, "Get information on attached devices");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
CreateOperation(operation_info, meta_data.get(), DEVICE_TYPES_INFO, "Get device properties by device type");
|
||||
CreateOperation(*operation_info, DEVICE_TYPES_INFO, "Get device properties by device type");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
operation = CreateOperation(*operation_info, DEFAULT_IMAGE_FILES_INFO, "Get information on available image files");
|
||||
if (depth) {
|
||||
AddOperationParameter(meta_data.get(), "folder_pattern", "Pattern for filtering image folder names");
|
||||
AddOperationParameter(*operation, "folder_pattern", "Pattern for filtering image folder names");
|
||||
}
|
||||
AddOperationParameter(meta_data.get(), "file_pattern", "Pattern for filtering image file names");
|
||||
CreateOperation(operation_info, meta_data.get(), DEFAULT_IMAGE_FILES_INFO, "Get information on available image files");
|
||||
AddOperationParameter(*operation, "file_pattern", "Pattern for filtering image file names");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
AddOperationParameter(meta_data.get(), "file", "Image file name", "", true);
|
||||
CreateOperation(operation_info, meta_data.get(), IMAGE_FILE_INFO, "Get information on image file");
|
||||
operation = CreateOperation(*operation_info, IMAGE_FILE_INFO, "Get information on image file");
|
||||
AddOperationParameter(*operation, "file", "Image file name", "", true);
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
CreateOperation(operation_info, meta_data.get(), LOG_LEVEL_INFO, "Get log level information");
|
||||
CreateOperation(*operation_info, LOG_LEVEL_INFO, "Get log level information");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
CreateOperation(operation_info, meta_data.get(), NETWORK_INTERFACES_INFO, "Get the available network interfaces");
|
||||
CreateOperation(*operation_info, NETWORK_INTERFACES_INFO, "Get the available network interfaces");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
CreateOperation(operation_info, meta_data.get(), MAPPING_INFO, "Get mapping of extensions to device types");
|
||||
CreateOperation(*operation_info, MAPPING_INFO, "Get mapping of extensions to device types");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
CreateOperation(operation_info, meta_data.get(), RESERVED_IDS_INFO, "Get list of reserved device IDs");
|
||||
CreateOperation(*operation_info, RESERVED_IDS_INFO, "Get list of reserved device IDs");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
AddOperationParameter(meta_data.get(), "folder", "Default image file folder name", "", true);
|
||||
CreateOperation(operation_info, meta_data.get(), DEFAULT_FOLDER, "Set default image file folder");
|
||||
operation = CreateOperation(*operation_info, DEFAULT_FOLDER, "Set default image file folder");
|
||||
AddOperationParameter(*operation, "folder", "Default image file folder name", "", true);
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
AddOperationParameter(meta_data.get(), "level", "New log level", "", true);
|
||||
CreateOperation(operation_info, meta_data.get(), LOG_LEVEL, "Set log level");
|
||||
operation = CreateOperation(*operation_info, LOG_LEVEL, "Set log level");
|
||||
AddOperationParameter(*operation, "level", "New log level", "", true);
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
AddOperationParameter(meta_data.get(), "ids", "Comma-separated device ID list", "", true);
|
||||
CreateOperation(operation_info, meta_data.get(), RESERVE_IDS, "Reserve device IDs");
|
||||
operation = CreateOperation(*operation_info, RESERVE_IDS, "Reserve device IDs");
|
||||
AddOperationParameter(*operation, "ids", "Comma-separated device ID list", "", true);
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
PbOperationParameter *parameter = AddOperationParameter(meta_data.get(), "mode", "Shutdown mode", "", true);
|
||||
operation = CreateOperation(*operation_info, SHUT_DOWN, "Shut down or reboot");
|
||||
PbOperationParameter *parameter = AddOperationParameter(*operation, "mode", "Shutdown mode", "", true);
|
||||
parameter->add_permitted_values("rascsi");
|
||||
// System shutdown/reboot requires root permissions
|
||||
if (!getuid()) {
|
||||
parameter->add_permitted_values("system");
|
||||
parameter->add_permitted_values("reboot");
|
||||
}
|
||||
CreateOperation(operation_info, meta_data.get(), SHUT_DOWN, "Shut down or reboot");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
AddOperationParameter(meta_data.get(), "file", "Image file name", "", true);
|
||||
AddOperationParameter(meta_data.get(), "size", "Image file size in bytes", "", true);
|
||||
parameter = AddOperationParameter(meta_data.get(), "read_only", "Read-only flag", "false");
|
||||
operation = CreateOperation(*operation_info, CREATE_IMAGE, "Create an image file");
|
||||
AddOperationParameter(*operation, "file", "Image file name", "", true);
|
||||
AddOperationParameter(*operation, "size", "Image file size in bytes", "", true);
|
||||
parameter = AddOperationParameter(*operation, "read_only", "Read-only flag", "false");
|
||||
parameter->add_permitted_values("true");
|
||||
parameter->add_permitted_values("false");
|
||||
CreateOperation(operation_info, meta_data.get(), CREATE_IMAGE, "Create an image file");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
AddOperationParameter(meta_data.get(), "file", "Image file name", "", true);
|
||||
CreateOperation(operation_info, meta_data.get(), DELETE_IMAGE, "Delete image file");
|
||||
operation = CreateOperation(*operation_info, DELETE_IMAGE, "Delete image file");
|
||||
AddOperationParameter(*operation, "file", "Image file name", "", true);
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
AddOperationParameter(meta_data.get(), "from", "Source image file name", "", true);
|
||||
AddOperationParameter(meta_data.get(), "to", "Destination image file name", "", true);
|
||||
CreateOperation(operation_info, meta_data.get(), RENAME_IMAGE, "Rename image file");
|
||||
operation = CreateOperation(*operation_info, RENAME_IMAGE, "Rename image file");
|
||||
AddOperationParameter(*operation, "from", "Source image file name", "", true);
|
||||
AddOperationParameter(*operation, "to", "Destination image file name", "", true);
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
AddOperationParameter(meta_data.get(), "from", "Source image file name", "", true);
|
||||
AddOperationParameter(meta_data.get(), "to", "Destination image file name", "", true);
|
||||
parameter = AddOperationParameter(meta_data.get(), "read_only", "Read-only flag", "false");
|
||||
operation = CreateOperation(*operation_info, COPY_IMAGE, "Copy image file");
|
||||
AddOperationParameter(*operation, "from", "Source image file name", "", true);
|
||||
AddOperationParameter(*operation, "to", "Destination image file name", "", true);
|
||||
parameter = AddOperationParameter(*operation, "read_only", "Read-only flag", "false");
|
||||
parameter->add_permitted_values("true");
|
||||
parameter->add_permitted_values("false");
|
||||
CreateOperation(operation_info, meta_data.get(), COPY_IMAGE, "Copy image file");
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
AddOperationParameter(meta_data.get(), "file", "Image file name", "", true);
|
||||
CreateOperation(operation_info, meta_data.get(), PROTECT_IMAGE, "Write-protect image file");
|
||||
operation = CreateOperation(*operation_info, PROTECT_IMAGE, "Write-protect image file");
|
||||
AddOperationParameter(*operation, "file", "Image file name", "", true);
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
AddOperationParameter(meta_data.get(), "file", "Image file name", "", true);
|
||||
CreateOperation(operation_info, meta_data.get(), UNPROTECT_IMAGE, "Make image file writable");
|
||||
operation = CreateOperation(*operation_info, UNPROTECT_IMAGE, "Make image file writable");
|
||||
AddOperationParameter(*operation, "file", "Image file name", "", true);
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
AddOperationParameter(meta_data.get(), "token", "Authentication token to be checked", "", true);
|
||||
CreateOperation(operation_info, meta_data.get(), CHECK_AUTHENTICATION, "Check whether an authentication token is valid");
|
||||
operation = CreateOperation(*operation_info, CHECK_AUTHENTICATION, "Check whether an authentication token is valid");
|
||||
AddOperationParameter(*operation, "token", "Authentication token to be checked", "", true);
|
||||
|
||||
meta_data = make_unique<PbOperationMetaData>();
|
||||
CreateOperation(operation_info, meta_data.get(), OPERATION_INFO, "Get operation meta data");
|
||||
CreateOperation(*operation_info, OPERATION_INFO, "Get operation meta data");
|
||||
|
||||
result.set_status(true);
|
||||
|
||||
return operation_info;
|
||||
return operation_info.release();
|
||||
}
|
||||
|
||||
void RascsiResponse::CreateOperation(PbOperationInfo *operation_info, PbOperationMetaData *meta_data,
|
||||
const PbOperation& operation, const string& description) const
|
||||
PbOperationMetaData *RascsiResponse::CreateOperation(PbOperationInfo& operation_info, const PbOperation& operation,
|
||||
const string& description) const
|
||||
{
|
||||
auto meta_data = make_unique<PbOperationMetaData>();
|
||||
meta_data->set_server_side_name(PbOperation_Name(operation));
|
||||
meta_data->set_description(description);
|
||||
int ordinal = PbOperation_descriptor()->FindValueByName(PbOperation_Name(operation))->index();
|
||||
(*operation_info->mutable_operations())[ordinal] = *meta_data;
|
||||
(*operation_info.mutable_operations())[ordinal] = *meta_data.release();
|
||||
return &(*operation_info.mutable_operations())[ordinal];
|
||||
}
|
||||
|
||||
PbOperationParameter *RascsiResponse::AddOperationParameter(PbOperationMetaData *meta_data, const string& name,
|
||||
PbOperationParameter *RascsiResponse::AddOperationParameter(PbOperationMetaData& meta_data, const string& name,
|
||||
const string& description, const string& default_value, bool is_mandatory)
|
||||
{
|
||||
PbOperationParameter *parameter = meta_data->add_parameters();
|
||||
auto parameter = unique_ptr<PbOperationParameter>(meta_data.add_parameters());
|
||||
parameter->set_name(name);
|
||||
parameter->set_description(description);
|
||||
parameter->set_default_value(default_value);
|
||||
parameter->set_is_mandatory(is_mandatory);
|
||||
|
||||
return parameter;
|
||||
return parameter.release();
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ private:
|
|||
DeviceFactory *device_factory;
|
||||
const RascsiImage *rascsi_image;
|
||||
|
||||
static list<string> log_levels;
|
||||
const list<string> log_levels = { "trace", "debug", "info", "warn", "err", "critical", "off" };
|
||||
|
||||
PbDeviceProperties *GetDeviceProperties(const Device *);
|
||||
void GetDevice(const Device *, PbDevice *);
|
||||
|
@ -57,7 +57,7 @@ private:
|
|||
void GetDeviceTypeProperties(PbDeviceTypesInfo&, PbDeviceType);
|
||||
void GetAvailableImages(PbImageFilesInfo&, string_view, const string&, const string&, const string&, int);
|
||||
void GetAvailableImages(PbResult& result, PbServerInfo&, const string&, const string&, int);
|
||||
void CreateOperation(PbOperationInfo *, PbOperationMetaData *, const PbOperation&, const string&) const;
|
||||
PbOperationParameter *AddOperationParameter(PbOperationMetaData *, const string&, const string&,
|
||||
PbOperationMetaData *CreateOperation(PbOperationInfo&, const PbOperation&, const string&) const;
|
||||
PbOperationParameter *AddOperationParameter(PbOperationMetaData&, const string&, const string&,
|
||||
const string& = "", bool = false);
|
||||
};
|
||||
|
|
|
@ -9,37 +9,29 @@
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "rascsi_version.h"
|
||||
#include <cstdio>
|
||||
#include <iomanip>
|
||||
|
||||
// The following should be updated for each release
|
||||
const int rascsi_major_version = 22; // Last two digits of year
|
||||
const int rascsi_minor_version = 9; // Month
|
||||
const int rascsi_patch_version = -1; // Patch number - increment for each update
|
||||
|
||||
static char rascsi_version_string[30]; // Allow for string up to "XX.XX.XXX" + null character + "development build"
|
||||
using namespace std;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Get the RaSCSI version string
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
const char* rascsi_get_version_string()
|
||||
string rascsi_get_version_string()
|
||||
{
|
||||
if(rascsi_patch_version < 0)
|
||||
{
|
||||
snprintf(rascsi_version_string, sizeof(rascsi_version_string),
|
||||
"%02d.%02d --DEVELOPMENT BUILD--",
|
||||
rascsi_major_version,
|
||||
rascsi_minor_version);
|
||||
stringstream s;
|
||||
|
||||
s << setw(2) << setfill('0') << rascsi_major_version << '.' << setw(2) << setfill('0') << rascsi_minor_version;
|
||||
|
||||
if (rascsi_patch_version < 0) {
|
||||
s << " --DEVELOPMENT BUILD--";
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(rascsi_version_string, sizeof(rascsi_version_string), "%02d.%02d.%d",
|
||||
rascsi_major_version,
|
||||
rascsi_minor_version,
|
||||
rascsi_patch_version);
|
||||
else {
|
||||
s << '.' << rascsi_patch_version;
|
||||
}
|
||||
return rascsi_version_string;
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,13 +9,10 @@
|
|||
//---------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
extern const int rascsi_major_version; // Last two digits of year
|
||||
extern const int rascsi_minor_version; // Month
|
||||
extern const int rascsi_patch_version; // Patch number
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Fetch the version string
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
const char* rascsi_get_version_string();
|
||||
std::string rascsi_get_version_string();
|
||||
|
|
|
@ -160,8 +160,8 @@ int main(int argc, char* argv[])
|
|||
string token;
|
||||
bool list = false;
|
||||
|
||||
string locale = setlocale(LC_MESSAGES, "");
|
||||
if (locale == "C") {
|
||||
const char *locale = setlocale(LC_MESSAGES, "");
|
||||
if (locale == nullptr || !strcmp(locale, "C")) {
|
||||
locale = "en";
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ bool Banner(int argc, char* argv[])
|
|||
{
|
||||
printf("RaSCSI hard disk dump utility ");
|
||||
printf("version %s (%s, %s)\n",
|
||||
rascsi_get_version_string(),
|
||||
rascsi_get_version_string().c_str(),
|
||||
__DATE__,
|
||||
__TIME__);
|
||||
|
||||
|
@ -100,7 +100,7 @@ bool Init()
|
|||
}
|
||||
|
||||
// GPIO Initialization
|
||||
if (!bus.Init(BUS::INITIATOR)) {
|
||||
if (!bus.Init(BUS::mode_e::INITIATOR)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -209,10 +209,8 @@ bool ParseArgument(int argc, char* argv[])
|
|||
//---------------------------------------------------------------------------
|
||||
bool WaitPhase(BUS::phase_t phase)
|
||||
{
|
||||
DWORD now;
|
||||
|
||||
// Timeout (3000ms)
|
||||
now = SysTimer::GetTimerLow();
|
||||
uint32_t now = SysTimer::GetTimerLow();
|
||||
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) {
|
||||
bus.Acquire();
|
||||
if (bus.GetREQ() && bus.GetPhase() == phase) {
|
||||
|
@ -278,7 +276,7 @@ bool Command(BYTE *buf, int length)
|
|||
int count;
|
||||
|
||||
// Waiting for Phase
|
||||
if (!WaitPhase(BUS::command)) {
|
||||
if (!WaitPhase(BUS::phase_t::command)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -303,7 +301,7 @@ bool Command(BYTE *buf, int length)
|
|||
int DataIn(BYTE *buf, int length)
|
||||
{
|
||||
// Wait for phase
|
||||
if (!WaitPhase(BUS::datain)) {
|
||||
if (!WaitPhase(BUS::phase_t::datain)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -319,7 +317,7 @@ int DataIn(BYTE *buf, int length)
|
|||
int DataOut(BYTE *buf, int length)
|
||||
{
|
||||
// Wait for phase
|
||||
if (!WaitPhase(BUS::dataout)) {
|
||||
if (!WaitPhase(BUS::phase_t::dataout)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -337,7 +335,7 @@ int Status()
|
|||
BYTE buf[256];
|
||||
|
||||
// Wait for phase
|
||||
if (!WaitPhase(BUS::status)) {
|
||||
if (!WaitPhase(BUS::phase_t::status)) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
@ -360,7 +358,7 @@ int MessageIn()
|
|||
BYTE buf[256];
|
||||
|
||||
// Wait for phase
|
||||
if (!WaitPhase(BUS::msgin)) {
|
||||
if (!WaitPhase(BUS::phase_t::msgin)) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
@ -838,9 +836,9 @@ int main(int argc, char* argv[])
|
|||
|
||||
// File Open
|
||||
if (restore) {
|
||||
omode = Fileio::ReadOnly;
|
||||
omode = Fileio::OpenMode::ReadOnly;
|
||||
} else {
|
||||
omode = Fileio::WriteOnly;
|
||||
omode = Fileio::OpenMode::WriteOnly;
|
||||
}
|
||||
if (!fio.Open(hdsfile.GetPath(), omode)) {
|
||||
fprintf(stderr, "Error : Can't open hds file\n");
|
||||
|
@ -854,9 +852,9 @@ int main(int argc, char* argv[])
|
|||
BusFree();
|
||||
|
||||
// Assert reset signal
|
||||
bus.SetRST(TRUE);
|
||||
bus.SetRST(true);
|
||||
usleep(1000);
|
||||
bus.SetRST(FALSE);
|
||||
bus.SetRST(false);
|
||||
|
||||
// Start dump
|
||||
printf("TARGET ID : %d\n", targetid);
|
||||
|
@ -953,16 +951,12 @@ int main(int argc, char* argv[])
|
|||
fflush(stdout);
|
||||
|
||||
if (restore) {
|
||||
if (fio.Read(buffer, dsiz)) {
|
||||
if (Write10(targetid, i * duni, duni, dsiz, buffer) >= 0) {
|
||||
continue;
|
||||
}
|
||||
if (fio.Read(buffer, dsiz) && Write10(targetid, i * duni, duni, dsiz, buffer) >= 0) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (Read10(targetid, i * duni, duni, dsiz, buffer) >= 0) {
|
||||
if (fio.Write(buffer, dsiz)) {
|
||||
continue;
|
||||
}
|
||||
if (Read10(targetid, i * duni, duni, dsiz, buffer) >= 0 && fio.Write(buffer, dsiz)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include "scsi.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Phase Acquisition
|
||||
|
@ -20,12 +22,12 @@ BUS::phase_t BUS::GetPhase()
|
|||
{
|
||||
// Selection Phase
|
||||
if (GetSEL()) {
|
||||
return selection;
|
||||
return phase_t::selection;
|
||||
}
|
||||
|
||||
// Bus busy phase
|
||||
if (!GetBSY()) {
|
||||
return busfree;
|
||||
return phase_t::busfree;
|
||||
}
|
||||
|
||||
// Get target phase from bus signal line
|
||||
|
@ -41,11 +43,10 @@ BUS::phase_t BUS::GetPhase()
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
const char* BUS::GetPhaseStrRaw(phase_t current_phase){
|
||||
if(current_phase <= phase_t::reserved){
|
||||
return phase_str_table[current_phase];
|
||||
if(current_phase <= phase_t::reserved) {
|
||||
return phase_str_table[(int)current_phase];
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
return "INVALID";
|
||||
}
|
||||
}
|
||||
|
@ -57,16 +58,16 @@ const char* BUS::GetPhaseStrRaw(phase_t current_phase){
|
|||
// This determines the phase based upon the Msg, C/D and I/O signals.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
const BUS::phase_t BUS::phase_table[8] = {
|
||||
// | MSG|C/D|I/O |
|
||||
dataout, // | 0 | 0 | 0 |
|
||||
datain, // | 0 | 0 | 1 |
|
||||
command, // | 0 | 1 | 0 |
|
||||
status, // | 0 | 1 | 1 |
|
||||
reserved, // | 1 | 0 | 0 |
|
||||
reserved, // | 1 | 0 | 1 |
|
||||
msgout, // | 1 | 1 | 0 |
|
||||
msgin // | 1 | 1 | 1 |
|
||||
const array<BUS::phase_t, 8> BUS::phase_table = {
|
||||
// | MSG|C/D|I/O |
|
||||
phase_t::dataout, // | 0 | 0 | 0 |
|
||||
phase_t::datain, // | 0 | 0 | 1 |
|
||||
phase_t::command, // | 0 | 1 | 0 |
|
||||
phase_t::status, // | 0 | 1 | 1 |
|
||||
phase_t::reserved, // | 1 | 0 | 0 |
|
||||
phase_t::reserved, // | 1 | 0 | 1 |
|
||||
phase_t::msgout, // | 1 | 1 | 0 |
|
||||
phase_t::msgin // | 1 | 1 | 1 |
|
||||
};
|
||||
|
||||
|
||||
|
@ -76,7 +77,7 @@ const BUS::phase_t BUS::phase_table[8] = {
|
|||
// This MUST be kept in sync with the phase_t enum type!
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
const char* BUS::phase_str_table[] = {
|
||||
const array<const char*, 12> BUS::phase_str_table = {
|
||||
"busfree",
|
||||
"arbitration",
|
||||
"selection",
|
||||
|
|
|
@ -10,7 +10,11 @@
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "os.h"
|
||||
#include <array>
|
||||
|
||||
using namespace std;
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
|
@ -21,14 +25,14 @@ class BUS
|
|||
{
|
||||
public:
|
||||
// Operation modes definition
|
||||
enum mode_e {
|
||||
enum class mode_e {
|
||||
TARGET = 0,
|
||||
INITIATOR = 1,
|
||||
MONITOR = 2,
|
||||
};
|
||||
|
||||
// Phase definitions
|
||||
enum phase_t : BYTE {
|
||||
enum class phase_t : BYTE {
|
||||
busfree,
|
||||
arbitration,
|
||||
selection,
|
||||
|
@ -97,7 +101,7 @@ public:
|
|||
virtual void SetDAT(BYTE dat) = 0;
|
||||
virtual bool GetDP() const = 0; // Get parity signal
|
||||
|
||||
virtual DWORD Acquire() = 0;
|
||||
virtual uint32_t Acquire() = 0;
|
||||
virtual int CommandHandShake(BYTE *buf) = 0;
|
||||
virtual int ReceiveHandShake(BYTE *buf, int count) = 0;
|
||||
virtual int SendHandShake(BYTE *buf, int count, int delay_after_bytes) = 0;
|
||||
|
@ -109,13 +113,13 @@ public:
|
|||
static const int SEND_NO_DELAY = -1;
|
||||
// Passed into SendHandShake when we don't want to delay
|
||||
private:
|
||||
static const phase_t phase_table[8];
|
||||
static const array<phase_t, 8> phase_table;
|
||||
|
||||
static const char* phase_str_table[];
|
||||
static const array<const char *, 12> phase_str_table;
|
||||
};
|
||||
|
||||
namespace scsi_defs {
|
||||
enum scsi_level : int {
|
||||
enum class scsi_level : int {
|
||||
SCSI_1_CCS = 1,
|
||||
SCSI_2 = 2,
|
||||
SPC = 3,
|
||||
|
@ -126,7 +130,7 @@ namespace scsi_defs {
|
|||
SPC_6 = 8
|
||||
};
|
||||
|
||||
enum device_type : int {
|
||||
enum class device_type : int {
|
||||
DIRECT_ACCESS = 0,
|
||||
PRINTER = 2,
|
||||
PROCESSOR = 3,
|
||||
|
@ -135,7 +139,7 @@ namespace scsi_defs {
|
|||
COMMUNICATIONS = 9
|
||||
};
|
||||
|
||||
enum scsi_command : int {
|
||||
enum class scsi_command : int {
|
||||
eCmdTestUnitReady = 0x00,
|
||||
eCmdRezero = 0x01,
|
||||
eCmdRequestSense = 0x03,
|
||||
|
@ -187,7 +191,7 @@ namespace scsi_defs {
|
|||
eCmdReportLuns = 0xA0
|
||||
};
|
||||
|
||||
enum status : int {
|
||||
enum class status : int {
|
||||
GOOD = 0x00,
|
||||
CHECK_CONDITION = 0x02,
|
||||
CONDITION_MET = 0x04,
|
||||
|
@ -199,7 +203,7 @@ namespace scsi_defs {
|
|||
QUEUE_FULL = 0x28
|
||||
};
|
||||
|
||||
enum sense_key : int {
|
||||
enum class sense_key : int {
|
||||
NO_SENSE = 0x00,
|
||||
RECOVERED_ERROR = 0x01,
|
||||
NOT_READY = 0x02,
|
||||
|
@ -217,7 +221,7 @@ namespace scsi_defs {
|
|||
COMPLETED = 0x0f
|
||||
};
|
||||
|
||||
enum asc : int {
|
||||
enum class asc : int {
|
||||
NO_ADDITIONAL_SENSE_INFORMATION = 0x00,
|
||||
WRITE_FAULT = 0x03,
|
||||
READ_FAULT = 0x11,
|
||||
|
|
|
@ -113,12 +113,12 @@ void print_copyright_text(int, char *[])
|
|||
{
|
||||
LOGINFO("SCSI Monitor Capture Tool - part of RaSCSI(*^..^*) ")
|
||||
LOGINFO("version %s (%s, %s)",
|
||||
rascsi_get_version_string(),
|
||||
rascsi_get_version_string().c_str(),
|
||||
__DATE__,
|
||||
__TIME__)
|
||||
LOGINFO("Powered by XM6 TypeG Technology ")
|
||||
LOGINFO("Copyright (C) 2016-2020 GIMONS")
|
||||
LOGINFO("Copyright (C) 2020-2021 Contributors to the RaSCSI project")
|
||||
LOGINFO("Copyright (C) 2020-2022 Contributors to the RaSCSI project")
|
||||
LOGINFO(" ")
|
||||
}
|
||||
|
||||
|
@ -171,15 +171,15 @@ bool Init()
|
|||
// Interrupt handler settings
|
||||
if (signal(SIGINT, KillHandler) == SIG_ERR)
|
||||
{
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
if (signal(SIGHUP, KillHandler) == SIG_ERR)
|
||||
{
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
if (signal(SIGTERM, KillHandler) == SIG_ERR)
|
||||
{
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// GPIO Initialization
|
||||
|
@ -335,7 +335,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
// Start execution
|
||||
running = true;
|
||||
bus->SetACT(FALSE);
|
||||
bus->SetACT(false);
|
||||
|
||||
(void)gettimeofday(&start_time, nullptr);
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ TEST(ControllerManagerTest, ControllerManager)
|
|||
{
|
||||
const int ID = 4;
|
||||
const int LUN = 6;
|
||||
ControllerManager controller_manager;
|
||||
|
||||
auto device = device_factory.CreateDevice(UNDEFINED, "services", ID);
|
||||
device->SetId(ID);
|
||||
|
|
|
@ -18,7 +18,7 @@ public:
|
|||
TestDevice() : Device("test") {}
|
||||
~TestDevice() final = default;
|
||||
|
||||
bool Dispatch() final { return false; }
|
||||
bool Dispatch(scsi_defs::scsi_command) final { return false; }
|
||||
};
|
||||
|
||||
TEST(DeviceTest, ProductData)
|
||||
|
|
|
@ -23,7 +23,7 @@ const unordered_set<uint32_t> sector_sizes;
|
|||
|
||||
TEST(ModePagesTest, ModePageDevice_AddModePages)
|
||||
{
|
||||
DWORD cdb[6];
|
||||
vector<int> cdb(6);
|
||||
BYTE buf[512];
|
||||
|
||||
MockModePageDevice device;
|
||||
|
@ -38,7 +38,7 @@ TEST(ModePagesTest, ModePageDevice_AddModePages)
|
|||
|
||||
TEST(ModePagesTest, SCSIHD_AddModePages)
|
||||
{
|
||||
map<int, vector<BYTE>> mode_pages;
|
||||
map<int, vector<byte>> mode_pages;
|
||||
|
||||
MockSCSIHD device(sector_sizes);
|
||||
device.AddModePages(mode_pages, 0x3f, false);
|
||||
|
@ -53,7 +53,7 @@ TEST(ModePagesTest, SCSIHD_AddModePages)
|
|||
|
||||
TEST(ModePagesTest, SCSIHD_NEC_AddModePages)
|
||||
{
|
||||
map<int, vector<BYTE>> mode_pages;
|
||||
map<int, vector<byte>> mode_pages;
|
||||
|
||||
MockSCSIHD_NEC device;
|
||||
device.AddModePages(mode_pages, 0x3f, false);
|
||||
|
@ -68,7 +68,7 @@ TEST(ModePagesTest, SCSIHD_NEC_AddModePages)
|
|||
|
||||
TEST(ModePagesTest, SCSICD_AddModePages)
|
||||
{
|
||||
map<int, vector<BYTE>> mode_pages;
|
||||
map<int, vector<byte>> mode_pages;
|
||||
|
||||
MockSCSICD device(sector_sizes);
|
||||
device.AddModePages(mode_pages, 0x3f, false);
|
||||
|
@ -85,7 +85,7 @@ TEST(ModePagesTest, SCSICD_AddModePages)
|
|||
|
||||
TEST(ModePagesTest, SCSIMO_AddModePages)
|
||||
{
|
||||
map<int, vector<BYTE>> mode_pages;
|
||||
map<int, vector<byte>> mode_pages;
|
||||
unordered_map<uint64_t, Geometry> geometries;
|
||||
|
||||
MockSCSIMO device(sector_sizes, geometries);
|
||||
|
@ -102,7 +102,7 @@ TEST(ModePagesTest, SCSIMO_AddModePages)
|
|||
|
||||
TEST(ModePagesTest, HostServices_AddModePages)
|
||||
{
|
||||
map<int, vector<BYTE>> mode_pages;
|
||||
map<int, vector<byte>> mode_pages;
|
||||
|
||||
MockHostServices device;
|
||||
device.AddModePages(mode_pages, 0x3f, false);
|
||||
|
@ -115,7 +115,7 @@ TEST(ModePagesTest, ModeSelect)
|
|||
{
|
||||
const int LENGTH = 12;
|
||||
|
||||
DWORD cdb[16] = {};
|
||||
vector<int> cdb(16);
|
||||
BYTE buf[255] = {};
|
||||
|
||||
// PF (vendor-specific parameter format)
|
||||
|
|
|
@ -19,36 +19,37 @@ TEST(PrimaryDeviceTest, UnitReady)
|
|||
|
||||
controller.AddDevice(&device);
|
||||
|
||||
controller.ctrl.cmd[0] = eCmdTestUnitReady;
|
||||
controller.ctrl.cmd = vector<int>(6);
|
||||
controller.ctrl.cmd[0] = (int)scsi_command::eCmdTestUnitReady;
|
||||
|
||||
device.SetReset(true);
|
||||
device.SetAttn(true);
|
||||
device.SetReady(false);
|
||||
EXPECT_CALL(controller, DataIn()).Times(0);
|
||||
EXPECT_THROW(device.Dispatch(), scsi_error_exception);
|
||||
EXPECT_THROW(device.Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
|
||||
|
||||
device.SetReset(false);
|
||||
EXPECT_CALL(controller, DataIn()).Times(0);
|
||||
EXPECT_THROW(device.Dispatch(), scsi_error_exception);
|
||||
EXPECT_THROW(device.Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
|
||||
|
||||
device.SetReset(true);
|
||||
device.SetAttn(false);
|
||||
EXPECT_CALL(controller, DataIn()).Times(0);
|
||||
EXPECT_THROW(device.Dispatch(), scsi_error_exception);
|
||||
EXPECT_THROW(device.Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
|
||||
|
||||
device.SetReset(false);
|
||||
device.SetAttn(true);
|
||||
EXPECT_CALL(controller, DataIn()).Times(0);
|
||||
EXPECT_THROW(device.Dispatch(), scsi_error_exception);
|
||||
EXPECT_THROW(device.Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
|
||||
|
||||
device.SetAttn(false);
|
||||
EXPECT_CALL(controller, DataIn()).Times(0);
|
||||
EXPECT_THROW(device.Dispatch(), scsi_error_exception);
|
||||
EXPECT_THROW(device.Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
|
||||
|
||||
device.SetReady(true);
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(device.Dispatch());
|
||||
EXPECT_TRUE(controller.ctrl.status == scsi_defs::status::GOOD);
|
||||
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdTestUnitReady));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
}
|
||||
|
||||
TEST(PrimaryDeviceTest, Inquiry)
|
||||
|
@ -58,7 +59,8 @@ TEST(PrimaryDeviceTest, Inquiry)
|
|||
|
||||
device.SetController(&controller);
|
||||
|
||||
controller.ctrl.cmd[0] = eCmdInquiry;
|
||||
controller.ctrl.cmd = vector<int>(6);
|
||||
controller.ctrl.cmd[0] = (int)scsi_command::eCmdInquiry;
|
||||
// ALLOCATION LENGTH
|
||||
controller.ctrl.cmd[4] = 255;
|
||||
|
||||
|
@ -67,18 +69,18 @@ TEST(PrimaryDeviceTest, Inquiry)
|
|||
});
|
||||
EXPECT_CALL(device, InquiryInternal()).Times(1);
|
||||
EXPECT_CALL(controller, DataIn()).Times(1);
|
||||
EXPECT_TRUE(device.Dispatch());
|
||||
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdInquiry));
|
||||
EXPECT_EQ(0x7F, controller.ctrl.buffer[0]) << "Invalid LUN was not reported";
|
||||
|
||||
EXPECT_TRUE(controller.AddDevice(&device));
|
||||
EXPECT_FALSE(controller.AddDevice(&device)) << "Duplicate LUN was not rejected";
|
||||
EXPECT_CALL(device, InquiryInternal()).Times(1);
|
||||
EXPECT_CALL(controller, DataIn()).Times(1);
|
||||
EXPECT_TRUE(device.Dispatch());
|
||||
EXPECT_EQ(device_type::PROCESSOR, controller.ctrl.buffer[0]);
|
||||
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdInquiry));
|
||||
EXPECT_EQ(device_type::PROCESSOR, (device_type)controller.ctrl.buffer[0]);
|
||||
EXPECT_EQ(0x00, controller.ctrl.buffer[1]) << "Device was not reported as non-removable";
|
||||
EXPECT_EQ(scsi_level::SPC_3, controller.ctrl.buffer[2]) << "Wrong SCSI level";
|
||||
EXPECT_EQ(scsi_level::SCSI_2, controller.ctrl.buffer[3]) << "Wrong response level";
|
||||
EXPECT_EQ(scsi_level::SPC_3, (scsi_level)controller.ctrl.buffer[2]) << "Wrong SCSI level";
|
||||
EXPECT_EQ(scsi_level::SCSI_2, (scsi_level)controller.ctrl.buffer[3]) << "Wrong response level";
|
||||
EXPECT_EQ(0x1F, controller.ctrl.buffer[4]) << "Wrong additional data size";
|
||||
|
||||
ON_CALL(device, InquiryInternal()).WillByDefault([&device]() {
|
||||
|
@ -86,20 +88,20 @@ TEST(PrimaryDeviceTest, Inquiry)
|
|||
});
|
||||
EXPECT_CALL(device, InquiryInternal()).Times(1);
|
||||
EXPECT_CALL(controller, DataIn()).Times(1);
|
||||
EXPECT_TRUE(device.Dispatch());
|
||||
EXPECT_EQ(device_type::DIRECT_ACCESS, controller.ctrl.buffer[0]);
|
||||
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdInquiry));
|
||||
EXPECT_EQ(device_type::DIRECT_ACCESS, (device_type)controller.ctrl.buffer[0]);
|
||||
EXPECT_EQ(0x80, controller.ctrl.buffer[1]) << "Device was not reported as removable";
|
||||
EXPECT_EQ(scsi_level::SCSI_1_CCS, controller.ctrl.buffer[2]) << "Wrong SCSI level";
|
||||
EXPECT_EQ(scsi_level::SCSI_1_CCS, controller.ctrl.buffer[3]) << "Wrong response level";
|
||||
EXPECT_EQ(scsi_level::SCSI_1_CCS, (scsi_level)controller.ctrl.buffer[2]) << "Wrong SCSI level";
|
||||
EXPECT_EQ(scsi_level::SCSI_1_CCS, (scsi_level)controller.ctrl.buffer[3]) << "Wrong response level";
|
||||
EXPECT_EQ(0x1F, controller.ctrl.buffer[4]) << "Wrong additional data size";
|
||||
|
||||
controller.ctrl.cmd[1] = 0x01;
|
||||
EXPECT_CALL(controller, DataIn()).Times(0);
|
||||
EXPECT_THROW(device.Dispatch(), scsi_error_exception) << "EVPD bit is not supported";
|
||||
EXPECT_THROW(device.Dispatch(scsi_command::eCmdInquiry), scsi_error_exception) << "EVPD bit is not supported";
|
||||
|
||||
controller.ctrl.cmd[2] = 0x01;
|
||||
EXPECT_CALL(controller, DataIn()).Times(0);
|
||||
EXPECT_THROW(device.Dispatch(), scsi_error_exception) << "PAGE CODE field is not supported";
|
||||
EXPECT_THROW(device.Dispatch(scsi_command::eCmdInquiry), scsi_error_exception) << "PAGE CODE field is not supported";
|
||||
|
||||
controller.ctrl.cmd[1] = 0x00;
|
||||
controller.ctrl.cmd[2] = 0x00;
|
||||
|
@ -107,7 +109,7 @@ TEST(PrimaryDeviceTest, Inquiry)
|
|||
controller.ctrl.cmd[4] = 1;
|
||||
EXPECT_CALL(device, InquiryInternal()).Times(1);
|
||||
EXPECT_CALL(controller, DataIn()).Times(1);
|
||||
EXPECT_TRUE(device.Dispatch());
|
||||
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdInquiry));
|
||||
EXPECT_EQ(0x1F, controller.ctrl.buffer[4]) << "Wrong additional data size";
|
||||
EXPECT_EQ(1, controller.ctrl.length) << "Wrong ALLOCATION LENGTH handling";
|
||||
}
|
||||
|
@ -119,17 +121,18 @@ TEST(PrimaryDeviceTest, RequestSense)
|
|||
|
||||
controller.AddDevice(&device);
|
||||
|
||||
controller.ctrl.cmd[0] = eCmdRequestSense;
|
||||
controller.ctrl.cmd = vector<int>(6);
|
||||
controller.ctrl.cmd[0] = (int)scsi_command::eCmdRequestSense;
|
||||
// ALLOCATION LENGTH
|
||||
controller.ctrl.cmd[4] = 255;
|
||||
|
||||
device.SetReady(false);
|
||||
EXPECT_THROW(device.Dispatch(), scsi_error_exception);
|
||||
EXPECT_THROW(device.Dispatch(scsi_command::eCmdRequestSense), scsi_error_exception);
|
||||
|
||||
device.SetReady(true);
|
||||
EXPECT_CALL(controller, DataIn()).Times(1);
|
||||
EXPECT_TRUE(device.Dispatch());
|
||||
EXPECT_TRUE(controller.ctrl.status == scsi_defs::status::GOOD);
|
||||
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdRequestSense));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
}
|
||||
|
||||
TEST(PrimaryDeviceTest, ReportLuns)
|
||||
|
@ -148,12 +151,13 @@ TEST(PrimaryDeviceTest, ReportLuns)
|
|||
controller.AddDevice(&device2);
|
||||
ASSERT_TRUE(controller.HasDeviceForLun(LUN2));
|
||||
|
||||
controller.ctrl.cmd[0] = eCmdReportLuns;
|
||||
controller.ctrl.cmd = vector<int>(10);
|
||||
controller.ctrl.cmd[0] = (int)scsi_command::eCmdReportLuns;
|
||||
// ALLOCATION LENGTH
|
||||
controller.ctrl.cmd[9] = 255;
|
||||
|
||||
EXPECT_CALL(controller, DataIn()).Times(1);
|
||||
EXPECT_TRUE(device1.Dispatch());
|
||||
EXPECT_TRUE(device1.Dispatch(scsi_command::eCmdReportLuns));
|
||||
const BYTE *buffer = controller.ctrl.buffer;
|
||||
EXPECT_EQ(0x00, buffer[0]) << "Wrong data length";
|
||||
EXPECT_EQ(0x00, buffer[1]) << "Wrong data length";
|
||||
|
@ -177,7 +181,7 @@ TEST(PrimaryDeviceTest, ReportLuns)
|
|||
EXPECT_EQ(LUN2, buffer[23]) << "Wrong LUN2 number";
|
||||
|
||||
controller.ctrl.cmd[2] = 0x01;
|
||||
EXPECT_THROW(device1.Dispatch(), scsi_error_exception) << "Only SELECT REPORT mode 0 is supported";
|
||||
EXPECT_THROW(device1.Dispatch(scsi_command::eCmdReportLuns), scsi_error_exception) << "Only SELECT REPORT mode 0 is supported";
|
||||
}
|
||||
|
||||
TEST(PrimaryDeviceTest, UnknownCommand)
|
||||
|
@ -187,6 +191,7 @@ TEST(PrimaryDeviceTest, UnknownCommand)
|
|||
|
||||
controller.AddDevice(&device);
|
||||
|
||||
controller.ctrl.cmd = vector<int>(1);
|
||||
controller.ctrl.cmd[0] = 0xFF;
|
||||
EXPECT_FALSE(device.Dispatch());
|
||||
EXPECT_FALSE(device.Dispatch((scsi_command)0xFF));
|
||||
}
|
||||
|
|
25
src/raspberrypi/test/response_test.cpp
Normal file
25
src/raspberrypi/test/response_test.cpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 Uwe Seimet
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "testing.h"
|
||||
#include "rascsi_interface.pb.h"
|
||||
#include "rascsi_response.h"
|
||||
#include "rascsi_image.h"
|
||||
|
||||
using namespace rascsi_interface;
|
||||
|
||||
TEST(ResponseTest, Operation_Count)
|
||||
{
|
||||
RascsiImage rascsi_image;
|
||||
RascsiResponse rascsi_response(&device_factory, &rascsi_image);
|
||||
PbResult pb_operation_info_result;
|
||||
|
||||
const auto operation_info = unique_ptr<PbOperationInfo>(rascsi_response.GetOperationInfo(pb_operation_info_result, 0));
|
||||
EXPECT_EQ(PbOperation_ARRAYSIZE - 1, operation_info->operations_size());
|
||||
}
|
45
src/raspberrypi/test/scsi_command_util_test.cpp
Normal file
45
src/raspberrypi/test/scsi_command_util_test.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 Uwe Seimet
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "testing.h"
|
||||
#include "devices/scsi_command_util.h"
|
||||
|
||||
TEST(ScsiCommandUtilTest, EnrichFormatPage)
|
||||
{
|
||||
const int SECTOR_SIZE = 512;
|
||||
|
||||
map<int, vector<byte>> pages;
|
||||
vector<byte> format_page(24);
|
||||
pages[3] = format_page;
|
||||
|
||||
scsi_command_util::EnrichFormatPage(pages, false, SECTOR_SIZE);
|
||||
format_page = pages[3];
|
||||
EXPECT_EQ(byte{0}, format_page[12]);
|
||||
EXPECT_EQ(byte{0}, format_page[13]);
|
||||
|
||||
scsi_command_util::EnrichFormatPage(pages, true, SECTOR_SIZE);
|
||||
format_page = pages[3];
|
||||
EXPECT_EQ(byte{SECTOR_SIZE >> 8}, format_page[12]);
|
||||
EXPECT_EQ(byte{0}, format_page[13]);
|
||||
}
|
||||
|
||||
TEST(ScsiCommandUtilTest, AddAppleVendorModePage)
|
||||
{
|
||||
map<int, vector<byte>> pages;
|
||||
vector<byte> vendor_page(30);
|
||||
pages[48] = vendor_page;
|
||||
|
||||
scsi_command_util::AddAppleVendorModePage(pages, true);
|
||||
vendor_page = pages[48];
|
||||
EXPECT_EQ(byte{0}, vendor_page[2]);
|
||||
|
||||
scsi_command_util::AddAppleVendorModePage(pages, false);
|
||||
vendor_page = pages[48];
|
||||
EXPECT_STREQ("APPLE COMPUTER, INC ", (const char *)&vendor_page[2]);
|
||||
}
|
|
@ -24,9 +24,7 @@ public:
|
|||
void SetUp() override { spdlog::set_level(spdlog::level::off); }
|
||||
};
|
||||
|
||||
DeviceFactory& device_factory = DeviceFactory::instance();
|
||||
|
||||
ControllerManager& controller_manager = ControllerManager::instance();
|
||||
const DeviceFactory& device_factory = DeviceFactory::instance();
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
// Note that these global variables are convenient,
|
||||
// but might cause issues because they are reused by all tests
|
||||
extern DeviceFactory& device_factory;
|
||||
extern ControllerManager& controller_manager;
|
||||
|
||||
class MockAbstractController : public AbstractController
|
||||
{
|
||||
|
@ -104,7 +103,7 @@ class MockPrimaryDevice : public PrimaryDevice
|
|||
{
|
||||
public:
|
||||
|
||||
MOCK_METHOD(vector<BYTE>, InquiryInternal, (), (const));
|
||||
MOCK_METHOD(vector<byte>, InquiryInternal, (), (const));
|
||||
|
||||
MockPrimaryDevice() : PrimaryDevice("test") {}
|
||||
~MockPrimaryDevice() final = default;
|
||||
|
@ -114,7 +113,7 @@ public:
|
|||
void SetReady(bool ready) { PrimaryDevice::SetReady(ready); }
|
||||
void SetReset(bool reset) { PrimaryDevice::SetReset(reset); }
|
||||
void SetAttn(bool attn) { PrimaryDevice::SetAttn(attn); }
|
||||
vector<BYTE> HandleInquiry(device_type type, scsi_level level, bool is_removable) const {
|
||||
vector<byte> HandleInquiry(device_type type, scsi_level level, bool is_removable) const {
|
||||
return PrimaryDevice::HandleInquiry(type, level, is_removable);
|
||||
}
|
||||
};
|
||||
|
@ -126,22 +125,20 @@ public:
|
|||
MockModePageDevice() : ModePageDevice("test") {}
|
||||
~MockModePageDevice() final = default;
|
||||
|
||||
MOCK_METHOD(vector<BYTE>, InquiryInternal, (), (const));
|
||||
MOCK_METHOD(int, ModeSense6, (const DWORD *, BYTE *, int), ());
|
||||
MOCK_METHOD(int, ModeSense10, (const DWORD *, BYTE *, int), ());
|
||||
MOCK_METHOD(vector<byte>, InquiryInternal, (), (const));
|
||||
MOCK_METHOD(int, ModeSense6, (const vector<int>&, BYTE *, int), (const override));
|
||||
MOCK_METHOD(int, ModeSense10, (const vector<int>&, BYTE *, int), (const override));
|
||||
|
||||
void AddModePages(map<int, vector<BYTE>>& pages, int page, bool) const override {
|
||||
void AddModePages(map<int, vector<byte>>& pages, int page, bool) const override {
|
||||
// Return dummy data for other pages than page 0
|
||||
if (page) {
|
||||
vector<BYTE> buf(255);
|
||||
vector<byte> buf(255);
|
||||
pages[page] = buf;
|
||||
}
|
||||
}
|
||||
|
||||
// Make protected methods visible for testing
|
||||
// TODO Why does FRIEND_TEST not work for this method?
|
||||
|
||||
int AddModePages(const DWORD *cdb, BYTE *buf, int max_length) const {
|
||||
// Make protected method visible for testing
|
||||
int AddModePages(const vector<int>& cdb, BYTE *buf, int max_length) const {
|
||||
return ModePageDevice::AddModePages(cdb, buf, max_length);
|
||||
}
|
||||
};
|
||||
|
@ -154,7 +151,7 @@ class MockSCSIHD : public SCSIHD
|
|||
~MockSCSIHD() final = default;
|
||||
};
|
||||
|
||||
class MockSCSIHD_NEC : public SCSIHD_NEC
|
||||
class MockSCSIHD_NEC : public SCSIHD_NEC //NOSONAR Ignore inheritance hierarchy depth in unit tests
|
||||
{
|
||||
FRIEND_TEST(ModePagesTest, SCSIHD_NEC_AddModePages);
|
||||
|
||||
|
@ -183,6 +180,8 @@ class MockHostServices : public HostServices
|
|||
{
|
||||
FRIEND_TEST(ModePagesTest, HostServices_AddModePages);
|
||||
|
||||
MockHostServices() = default;
|
||||
public:
|
||||
|
||||
MockHostServices() : HostServices(&DeviceFactory::instance()) {}
|
||||
~MockHostServices() final = default;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user