1
0
mirror of https://github.com/livingcomputermuseum/UniBone.git synced 2026-01-27 20:37:36 +00:00
Files
livingcomputermuseum.UniBone/10.02_devices/2_src/mscp_drive.cpp
Josh Dersch 398c54ee3f Fixed Unit and Controller ID fields (word order was scrambled) and removed hacked-in constant values for same.
Made RCT table size dynamic based on the drive type.

The above allow RSTS/E to boot!  Huzzah!
2019-05-17 00:47:11 +02:00

292 lines
5.8 KiB
C++

/*
mscp_drive.cpp: Implementation of MSCP disks.
*/
#include <assert.h>
#include <memory>
using namespace std;
#include "logger.hpp"
#include "utils.hpp"
#include "mscp_drive.hpp"
#include "mscp_server.hpp"
mscp_drive_c::mscp_drive_c(
storagecontroller_c *controller,
uint32_t driveNumber) :
storagedrive_c(controller),
_useImageSize(false)
{
log_label = "MSCPD";
SetDriveType("RA81");
SetOffline();
// Calculate the unit's ID:
_unitIDDeviceNumber = driveNumber + 1;
}
mscp_drive_c::~mscp_drive_c()
{
if (file_is_open())
{
file_close();
}
}
uint32_t mscp_drive_c::GetBlockSize()
{
//
// For the time being this is always 512 bytes.
//
return 512;
}
uint32_t mscp_drive_c::GetBlockCount()
{
if (_useImageSize)
{
// Return the image size / Block size (rounding down).
return file_size() / GetBlockSize();
}
else
{
//
// Use the size defined by the drive type.
//
return _driveInfo.BlockCount;
}
}
uint32_t mscp_drive_c::GetRCTBlockCount()
{
return _driveInfo.RCTSize * GetRCTCopies();
}
uint32_t mscp_drive_c::GetMediaID()
{
return _driveInfo.MediaID;
}
uint32_t mscp_drive_c::GetUnitIDDeviceNumber()
{
return _unitIDDeviceNumber;
}
uint16_t mscp_drive_c::GetUnitIDClassModel()
{
return _unitIDClassModel;
}
uint16_t mscp_drive_c::GetRCTSize()
{
return _driveInfo.RCTSize;
}
uint8_t mscp_drive_c::GetRBNs()
{
return 0;
}
uint8_t mscp_drive_c::GetRCTCopies()
{
return 1;
}
bool mscp_drive_c::IsAvailable()
{
return file_is_open();
}
bool mscp_drive_c::IsOnline()
{
return _online;
}
void mscp_drive_c::SetOnline()
{
_online = true;
//
// Once online, the drive's type and image cannot be changed until
// the drive is offline.
//
type_name.readonly = true;
image_filepath.readonly = true;
}
void mscp_drive_c::SetOffline()
{
_online = false;
type_name.readonly = false;
image_filepath.readonly = false;
}
//
// Writes the specified number of bytes from the provided buffer,
// starting at the specified logical block.
//
void mscp_drive_c::Write(
uint32_t blockNumber,
size_t lengthInBytes,
uint8_t* buffer)
{
file_write(
buffer,
blockNumber * GetBlockSize(),
lengthInBytes);
}
//
// Reads the specifed number of bytes starting at the specified logical
// block. Returns a pointer to a buffer containing the data read.
// Caller is responsible for freeing this buffer.
//
uint8_t* mscp_drive_c::Read(
uint32_t blockNumber,
size_t lengthInBytes)
{
uint8_t* buffer = new uint8_t[lengthInBytes];
assert(nullptr != buffer);
file_read(
buffer,
blockNumber * GetBlockSize(),
lengthInBytes);
return buffer;
}
//
// Writes a single block's worth of data from the provided buffer into the
// RCT area at the specified RCT block. Buffer must be at least as large
// as the disk's block size.
//
void mscp_drive_c::WriteRCTBlock(
uint32_t rctBlockNumber,
uint8_t* buffer)
{
assert (rctBlockNumber < GetRCTBlockCount());
memcpy(
reinterpret_cast<void *>(_rctData.get() + rctBlockNumber * GetBlockSize()),
reinterpret_cast<void *>(buffer),
GetBlockSize());
}
//
// Reads a single block's worth of data from the RCT area (at the specified
// block offset). Returns a pointer to a buffer containing the data read.
// Caller is responsible for freeing this buffer.
//
uint8_t* mscp_drive_c::ReadRCTBlock(
uint32_t rctBlockNumber)
{
assert (rctBlockNumber < GetRCTBlockCount());
uint8_t* buffer = new uint8_t[GetBlockSize()];
assert (nullptr != buffer);
memcpy(
reinterpret_cast<void *>(buffer),
reinterpret_cast<void *>(_rctData.get() + rctBlockNumber * GetBlockSize()),
GetBlockSize());
return buffer;
}
void mscp_drive_c::UpdateCapacity()
{
capacity.value =
GetBlockCount() * GetBlockSize();
}
void mscp_drive_c::UpdateMetadata()
{
_unitIDClassModel = 0x0200 | _driveInfo.Model;
// Initialize the RCT area
size_t rctSize = _driveInfo.RCTSize * GetBlockSize();
_rctData.reset(new uint8_t[rctSize]);
assert(_rctData != nullptr);
memset(reinterpret_cast<void *>(_rctData.get()), 0, rctSize);
}
bool mscp_drive_c::on_param_changed(
parameter_c *param)
{
if (&type_name == param)
{
return SetDriveType(type_name.new_value.c_str());
}
else if (&image_filepath == param)
{
//
// Try to open the image file.
//
if (file_open(image_filepath.new_value, true))
{
image_filepath.value = image_filepath.new_value;
UpdateCapacity();
return true;
}
//
// TODO: if file is a nonstandard size?
}
else if (&use_image_size == param)
{
_useImageSize = use_image_size.new_value;
use_image_size.value = use_image_size.new_value;
UpdateCapacity();
return true;
}
return false;
}
bool mscp_drive_c::SetDriveType(const char* typeName)
{
//
// Search through drive data table for name,
// and if valid, set the type appropriately.
//
int index = 0;
while (g_driveTable[index].BlockCount != 0)
{
if (!strcasecmp(typeName, g_driveTable[index].TypeName))
{
_driveInfo = g_driveTable[index];
type_name.value = _driveInfo.TypeName;
UpdateCapacity();
UpdateMetadata();
return true;
}
index++;
}
// Not found
return false;
}
void mscp_drive_c::worker(void)
{
// Nothing to do here at the moment.
}
void mscp_drive_c::on_power_changed(void)
{
// Take the drive offline due to power change
SetOffline();
}
void mscp_drive_c::on_init_changed(void)
{
// Take the drive offline due to reset
SetOffline();
}