mirror of https://github.com/akuker/RASCSI.git
Added posix file i/o functionality
This commit is contained in:
parent
33d9864573
commit
7416429c55
|
@ -104,6 +104,7 @@ SRC_RASCSI = \
|
|||
localizer.cpp
|
||||
SRC_RASCSI += $(shell find ./controllers -name '*.cpp')
|
||||
SRC_RASCSI += $(shell find ./devices -name '*.cpp')
|
||||
SRC_RASCSI += $(shell find ./file_access -name '*.cpp')
|
||||
SRC_RASCSI += $(SRC_PROTOBUF)
|
||||
|
||||
SRC_SCSIMON = \
|
||||
|
@ -139,8 +140,8 @@ SRC_SASIDUMP = \
|
|||
fileio.cpp\
|
||||
rascsi_version.cpp
|
||||
|
||||
vpath %.h ./ ./controllers ./devices ./monitor
|
||||
vpath %.cpp ./ ./controllers ./devices ./monitor
|
||||
vpath %.h ./ ./controllers ./devices ./file_access ./monitor
|
||||
vpath %.cpp ./ ./controllers ./devices ./file_access ./monitor
|
||||
vpath %.o ./$(OBJDIR)
|
||||
vpath ./$(BINDIR)
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "disk.h"
|
||||
#include <sstream>
|
||||
#include "../rascsi.h"
|
||||
#include "file_access/file_access_factory.h"
|
||||
|
||||
Disk::Disk(const std::string id) : Device(id), ScsiPrimaryCommands(), ScsiBlockCommands()
|
||||
{
|
||||
|
@ -76,7 +77,7 @@ Disk::~Disk()
|
|||
if (IsReady()) {
|
||||
// Only if ready...
|
||||
if (disk.dcache) {
|
||||
// disk.dcache->Save();
|
||||
disk.dcache->Save();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,7 +129,7 @@ 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 = FileAccessFactory::CreateFileAccess(path, disk.size, disk.blocks, disk.image_offset);
|
||||
|
||||
// Can read/write open
|
||||
Fileio fio;
|
||||
|
@ -517,8 +518,8 @@ void Disk::PreventAllowMediumRemoval(SASIDEV *controller)
|
|||
|
||||
void Disk::SynchronizeCache10(SASIDEV *controller)
|
||||
{
|
||||
// Flush the RaSCSI cache
|
||||
// disk.dcache->Save();
|
||||
//Flush the RaSCSI cache
|
||||
disk.dcache->Save();
|
||||
|
||||
controller->Status();
|
||||
}
|
||||
|
@ -544,7 +545,7 @@ bool Disk::Eject(bool force)
|
|||
bool status = Device::Eject(force);
|
||||
if (status) {
|
||||
// Remove disk cache
|
||||
// disk.dcache->Save();
|
||||
disk.dcache->Save();
|
||||
delete disk.dcache;
|
||||
disk.dcache = NULL;
|
||||
|
||||
|
@ -1295,7 +1296,7 @@ bool Disk::StartStop(const DWORD *cdb)
|
|||
|
||||
if (!start) {
|
||||
// Flush the cache when stopping
|
||||
// disk.dcache->Save();
|
||||
disk.dcache->Save();
|
||||
|
||||
// Look at the eject bit and eject if necessary
|
||||
if (load) {
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "controllers/scsidev_ctrl.h"
|
||||
#include "device.h"
|
||||
#include "device_factory.h"
|
||||
#include "disk_track_cache.h"
|
||||
#include "file_access/file_access.h"
|
||||
#include "file_support.h"
|
||||
#include "filepath.h"
|
||||
#include <string>
|
||||
|
@ -51,7 +51,7 @@ private:
|
|||
uint32_t size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096)
|
||||
// TODO blocks should be a 64 bit value in order to support higher capacities
|
||||
uint32_t blocks; // Total number of sectors
|
||||
DiskCache *dcache; // Disk cache
|
||||
FileAccess *dcache; // Disk cache
|
||||
off_t image_offset; // Offset to actual data
|
||||
} disk_t;
|
||||
|
||||
|
|
|
@ -1,174 +0,0 @@
|
|||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// X68000 EMULATOR "XM6"
|
||||
//
|
||||
// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp)
|
||||
// Copyright (C) 2014-2020 GIMONS
|
||||
//
|
||||
// XM6i
|
||||
// Copyright (C) 2010-2015 isaki@NetBSD.org
|
||||
// Copyright (C) 2010 Y.Sugahara
|
||||
//
|
||||
// Imported sava's Anex86/T98Next image and MO format support patch.
|
||||
// Imported NetBSD support and some optimisation patch by Rin Okuyama.
|
||||
// Comments translated to english by akuker.
|
||||
//
|
||||
// [ DiskTrack and DiskCache ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "os.h"
|
||||
#include "log.h"
|
||||
#include "fileio.h"
|
||||
#include "disk_track_cache.h"
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Disk Cache
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
DiskCache::DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgoff)
|
||||
{
|
||||
ASSERT(blocks > 0);
|
||||
ASSERT(imgoff >= 0);
|
||||
|
||||
initialized = false;
|
||||
|
||||
// Other
|
||||
serial = 0;
|
||||
sec_path = path;
|
||||
sec_size = size;
|
||||
sec_blocks = blocks;
|
||||
cd_raw = FALSE;
|
||||
imgoffset = imgoff;
|
||||
|
||||
fd = open(path.GetPath(), O_RDWR);
|
||||
if(fd < 0){
|
||||
LOGWARN("Unable to open file %s. Errno:%d", path.GetPath(), errno)
|
||||
}
|
||||
struct stat sb;
|
||||
if(fstat(fd, &sb) < 0){
|
||||
LOGWARN("Unable to run fstat. Errno:%d", errno);
|
||||
}
|
||||
printf("Size: %llu\n", (uint64_t)sb.st_size);
|
||||
|
||||
// int x = EACCES;
|
||||
|
||||
memory_block = (const char*)mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
int errno_val = errno;
|
||||
if (memory_block == MAP_FAILED) {
|
||||
LOGWARN("Unabled to memory map file %s", path.GetPath());
|
||||
LOGWARN(" Errno:%d", errno_val);
|
||||
errno_val = EACCES;
|
||||
}
|
||||
|
||||
|
||||
initialized = true;
|
||||
|
||||
}
|
||||
|
||||
DiskCache::~DiskCache()
|
||||
{
|
||||
munmap((void*)memory_block, sb.st_size);
|
||||
close(fd);
|
||||
// Clear the track
|
||||
// Clear();
|
||||
}
|
||||
|
||||
void DiskCache::SetRawMode(BOOL raw)
|
||||
{
|
||||
// Configuration
|
||||
cd_raw = raw;
|
||||
}
|
||||
|
||||
|
||||
bool DiskCache::ReadSector(BYTE *buf, int block)
|
||||
{
|
||||
ASSERT(sec_size != 0);
|
||||
ASSERT(buf);
|
||||
ASSERT(block < sec_blocks);
|
||||
ASSERT(memory_block);
|
||||
|
||||
if(!initialized){
|
||||
return false;
|
||||
}
|
||||
|
||||
int sector_size_bytes = (off_t)1 << sec_size;
|
||||
|
||||
// Calculate offset into the image file
|
||||
off_t offset = GetTrackOffset(block);
|
||||
offset += GetSectorOffset(block);
|
||||
LOGWARN("%s track:%d sector:%d offset:%llu block:%d size:%d", __PRETTY_FUNCTION__, (block >>8), (block & 0xff), offset, block, sector_size_bytes);
|
||||
|
||||
// LOGINFO("Reading data track:%d sec_size:%d block:%d offset: %lld imgoffset: %lld", track, sec_size, block, offset, imgoffset);
|
||||
|
||||
memcpy(buf, &memory_block[offset], sector_size_bytes);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool DiskCache::WriteSector(const BYTE *buf, int block)
|
||||
{
|
||||
ASSERT(buf);
|
||||
ASSERT(block < sec_blocks);
|
||||
ASSERT(memory_block);
|
||||
|
||||
if(!initialized){
|
||||
return false;
|
||||
}
|
||||
|
||||
int sector_size_bytes = (off_t)1 << sec_size;
|
||||
|
||||
// Calculate offset into the image file
|
||||
off_t offset = GetTrackOffset(block);
|
||||
offset += GetSectorOffset(block);
|
||||
LOGWARN("%s track:%d sector:%d offset:%llu block:%d size:%d", __PRETTY_FUNCTION__, (block >>8), (block & 0xff), offset, block, sector_size_bytes);
|
||||
|
||||
memcpy((void*)&memory_block[offset], buf, sector_size_bytes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
off_t DiskCache::GetSectorOffset(int block){
|
||||
|
||||
int sector_num = block & 0xff;
|
||||
|
||||
// // // Error if the number of sectors exceeds the valid number
|
||||
// if (sector_num >= sectors) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
return (off_t)sector_num << sec_size;
|
||||
}
|
||||
|
||||
off_t DiskCache::GetTrackOffset(int block){
|
||||
|
||||
// Assuming that all tracks hold 256 sectors
|
||||
int track_num = block >> 8;
|
||||
|
||||
// Calculate offset (previous tracks are considered to hold 256 sectors)
|
||||
off_t offset = ((off_t)track_num << 8);
|
||||
if (cd_raw) {
|
||||
ASSERT(sec_size == 11);
|
||||
offset *= 0x930;
|
||||
offset += 0x10;
|
||||
} else {
|
||||
offset <<= sec_size;
|
||||
}
|
||||
|
||||
// Add offset to real image
|
||||
offset += imgoffset;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
// off_t DiskCache::GetTrackSize(){
|
||||
// // Calculate length (data size of this track)
|
||||
// off_t length = sectors << sec_size;
|
||||
// return length;
|
||||
// }
|
|
@ -19,6 +19,7 @@
|
|||
#include "exceptions.h"
|
||||
#include <sstream>
|
||||
#include "../rascsi.h"
|
||||
#include "file_access/file_access_factory.h"
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
|
@ -599,7 +600,7 @@ int SCSICD::Read(const DWORD *cdb, BYTE *buf, uint64_t block)
|
|||
// Recreate the disk cache
|
||||
Filepath path;
|
||||
track[index]->GetPath(path);
|
||||
disk.dcache = new DiskCache(path, GetSectorSizeShiftCount(), GetBlockCount());
|
||||
disk.dcache = FileAccessFactory::CreateFileAccess(path, GetSectorSizeShiftCount(), GetBlockCount());
|
||||
disk.dcache->SetRawMode(rawfile);
|
||||
|
||||
// Reset data index
|
||||
|
|
|
@ -0,0 +1,576 @@
|
|||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// X68000 EMULATOR "XM6"
|
||||
//
|
||||
// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp)
|
||||
// Copyright (C) 2014-2020 GIMONS
|
||||
//
|
||||
// XM6i
|
||||
// Copyright (C) 2010-2015 isaki@NetBSD.org
|
||||
// Copyright (C) 2010 Y.Sugahara
|
||||
//
|
||||
// Imported sava's Anex86/T98Next image and MO format support patch.
|
||||
// Imported NetBSD support and some optimisation patch by Rin Okuyama.
|
||||
// Comments translated to english by akuker.
|
||||
//
|
||||
// [ DiskTrack and DiskCache ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "os.h"
|
||||
#include "log.h"
|
||||
#include "fileio.h"
|
||||
#include "disk_track_cache.h"
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Disk Track
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
DiskTrack::DiskTrack()
|
||||
{
|
||||
// Initialization of internal information
|
||||
dt.track = 0;
|
||||
dt.size = 0;
|
||||
dt.sectors = 0;
|
||||
dt.raw = FALSE;
|
||||
dt.init = FALSE;
|
||||
dt.changed = FALSE;
|
||||
dt.length = 0;
|
||||
dt.buffer = NULL;
|
||||
dt.maplen = 0;
|
||||
dt.changemap = NULL;
|
||||
dt.imgoffset = 0;
|
||||
}
|
||||
|
||||
DiskTrack::~DiskTrack()
|
||||
{
|
||||
// Release memory, but do not save automatically
|
||||
if (dt.buffer) {
|
||||
free(dt.buffer);
|
||||
dt.buffer = NULL;
|
||||
}
|
||||
if (dt.changemap) {
|
||||
free(dt.changemap);
|
||||
dt.changemap = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// Set Parameters
|
||||
dt.track = track;
|
||||
dt.size = size;
|
||||
dt.sectors = sectors;
|
||||
dt.raw = raw;
|
||||
|
||||
// Not initialized (needs to be loaded)
|
||||
dt.init = FALSE;
|
||||
|
||||
// Not Changed
|
||||
dt.changed = FALSE;
|
||||
|
||||
// Offset to actual data
|
||||
dt.imgoffset = imgoff;
|
||||
}
|
||||
|
||||
bool DiskTrack::Load(const Filepath& path)
|
||||
{
|
||||
// Not needed if already loaded
|
||||
if (dt.init) {
|
||||
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);
|
||||
offset *= 0x930;
|
||||
offset += 0x10;
|
||||
} else {
|
||||
offset <<= dt.size;
|
||||
}
|
||||
|
||||
// Add offset to real image
|
||||
offset += dt.imgoffset;
|
||||
|
||||
// Calculate length (data size of this track)
|
||||
int length = dt.sectors << dt.size;
|
||||
|
||||
// Allocate buffer memory
|
||||
ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100));
|
||||
|
||||
if (dt.buffer == NULL) {
|
||||
if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) {
|
||||
LOGWARN("%s posix_memalign failed", __PRETTY_FUNCTION__);
|
||||
}
|
||||
dt.length = length;
|
||||
}
|
||||
|
||||
if (!dt.buffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reallocate if the buffer length is different
|
||||
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__);
|
||||
}
|
||||
dt.length = length;
|
||||
}
|
||||
|
||||
// Reserve change map memory
|
||||
if (dt.changemap == NULL) {
|
||||
dt.changemap = (BOOL *)malloc(dt.sectors * sizeof(BOOL));
|
||||
dt.maplen = dt.sectors;
|
||||
}
|
||||
|
||||
if (!dt.changemap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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.maplen = dt.sectors;
|
||||
}
|
||||
|
||||
// Clear changemap
|
||||
memset(dt.changemap, 0x00, dt.sectors * sizeof(BOOL));
|
||||
|
||||
// Read from File
|
||||
Fileio fio;
|
||||
if (!fio.OpenDIO(path, Fileio::ReadOnly)) {
|
||||
return false;
|
||||
}
|
||||
if (dt.raw) {
|
||||
// Split Reading
|
||||
for (int i = 0; i < dt.sectors; i++) {
|
||||
// Seek
|
||||
if (!fio.Seek(offset)) {
|
||||
fio.Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read
|
||||
if (!fio.Read(&dt.buffer[i << dt.size], 1 << dt.size)) {
|
||||
fio.Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Next offset
|
||||
offset += 0x930;
|
||||
}
|
||||
} else {
|
||||
// Continuous reading
|
||||
if (!fio.Seek(offset)) {
|
||||
fio.Close();
|
||||
return false;
|
||||
}
|
||||
if (!fio.Read(dt.buffer, length)) {
|
||||
fio.Close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
fio.Close();
|
||||
|
||||
// Set a flag and end normally
|
||||
dt.init = TRUE;
|
||||
dt.changed = FALSE;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiskTrack::Save(const Filepath& path)
|
||||
{
|
||||
// Not needed if not initialized
|
||||
if (!dt.init) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Not needed unless changed
|
||||
if (!dt.changed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Need to write
|
||||
ASSERT(dt.buffer);
|
||||
ASSERT(dt.changemap);
|
||||
ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100));
|
||||
|
||||
// Writing in RAW mode is not allowed
|
||||
ASSERT(!dt.raw);
|
||||
|
||||
// Calculate offset (previous tracks are considered to hold 256 sectors)
|
||||
off_t offset = ((off_t)dt.track << 8);
|
||||
offset <<= dt.size;
|
||||
|
||||
// Add offset to real image
|
||||
offset += dt.imgoffset;
|
||||
|
||||
// Calculate length per sector
|
||||
int length = 1 << dt.size;
|
||||
|
||||
// Open file
|
||||
Fileio fio;
|
||||
if (!fio.Open(path, Fileio::ReadWrite)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Partial write loop
|
||||
int total;
|
||||
for (int i = 0; i < dt.sectors;) {
|
||||
// If changed
|
||||
if (dt.changemap[i]) {
|
||||
// Initialize write size
|
||||
total = 0;
|
||||
|
||||
// Seek
|
||||
if (!fio.Seek(offset + ((off_t)i << dt.size))) {
|
||||
fio.Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Consectutive sector length
|
||||
int j;
|
||||
for (j = i; j < dt.sectors; j++) {
|
||||
// end when interrupted
|
||||
if (!dt.changemap[j]) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Add one sector
|
||||
total += length;
|
||||
}
|
||||
|
||||
// Write
|
||||
if (!fio.Write(&dt.buffer[i << dt.size], total)) {
|
||||
fio.Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// To unmodified sector
|
||||
i = j;
|
||||
} else {
|
||||
// Next Sector
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// Close
|
||||
fio.Close();
|
||||
|
||||
// Drop the change flag and exit
|
||||
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));
|
||||
|
||||
LOGTRACE("%s reading sector: %d", __PRETTY_FUNCTION__,sec);
|
||||
// Error if not initialized
|
||||
if (!dt.init) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// // Error if the number of sectors exceeds the valid number
|
||||
if (sec >= dt.sectors) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy
|
||||
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
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiskTrack::WriteSector(const BYTE *buf, int sec)
|
||||
{
|
||||
ASSERT(buf);
|
||||
ASSERT((sec >= 0) & (sec < 0x100));
|
||||
ASSERT(!dt.raw);
|
||||
|
||||
// Error if not initialized
|
||||
if (!dt.init) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// // Error if the number of sectors exceeds the valid number
|
||||
if (sec >= dt.sectors) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate offset and length
|
||||
int offset = sec << dt.size;
|
||||
int length = 1 << dt.size;
|
||||
|
||||
// Compare
|
||||
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;
|
||||
}
|
||||
|
||||
// Copy, change
|
||||
memcpy(&dt.buffer[offset], buf, length);
|
||||
dt.changemap[sec] = TRUE;
|
||||
dt.changed = TRUE;
|
||||
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Disk Cache
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
DiskCache::DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgoff) : FileAccess(path, size, blocks, imgoff)
|
||||
{
|
||||
ASSERT(blocks > 0);
|
||||
ASSERT(imgoff >= 0);
|
||||
|
||||
// Cache work
|
||||
for (int i = 0; i < CacheMax; i++) {
|
||||
cache[i].disktrk = NULL;
|
||||
cache[i].serial = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DiskCache::~DiskCache()
|
||||
{
|
||||
// Clear the track
|
||||
Clear();
|
||||
}
|
||||
|
||||
bool DiskCache::Save()
|
||||
{
|
||||
// Save track
|
||||
for (int i = 0; i < CacheMax; i++) {
|
||||
// Is it a valid track?
|
||||
if (cache[i].disktrk) {
|
||||
// Save
|
||||
if (!cache[i].disktrk->Save(sec_path)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Get disk cache information
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool DiskCache::GetCache(int index, int& track, DWORD& aserial) const
|
||||
{
|
||||
ASSERT((index >= 0) && (index < CacheMax));
|
||||
|
||||
// false if unused
|
||||
if (!cache[index].disktrk) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set track and serial
|
||||
track = cache[index].disktrk->GetTrack();
|
||||
aserial = cache[index].serial;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DiskCache::Clear()
|
||||
{
|
||||
// Free the cache
|
||||
for (int i = 0; i < CacheMax; i++) {
|
||||
if (cache[i].disktrk) {
|
||||
delete cache[i].disktrk;
|
||||
cache[i].disktrk = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DiskCache::ReadSector(BYTE *buf, int block)
|
||||
{
|
||||
ASSERT(sec_size != 0);
|
||||
|
||||
// Update first
|
||||
UpdateSerialNumber();
|
||||
|
||||
// Calculate track (fixed to 256 sectors/track)
|
||||
int track = block >> 8;
|
||||
|
||||
// Get the track data
|
||||
DiskTrack *disktrk = Assign(track);
|
||||
if (!disktrk) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the track data to the cache
|
||||
return disktrk->ReadSector(buf, block & 0xff);
|
||||
}
|
||||
|
||||
bool DiskCache::WriteSector(const BYTE *buf, int block)
|
||||
{
|
||||
ASSERT(sec_size != 0);
|
||||
|
||||
// Update first
|
||||
UpdateSerialNumber();
|
||||
|
||||
// Calculate track (fixed to 256 sectors/track)
|
||||
int track = block >> 8;
|
||||
|
||||
// Get that track data
|
||||
DiskTrack *disktrk = Assign(track);
|
||||
if (!disktrk) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write the data to the cache
|
||||
return disktrk->WriteSector(buf, block & 0xff);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Track Assignment
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
DiskTrack* DiskCache::Assign(int track)
|
||||
{
|
||||
ASSERT(sec_size != 0);
|
||||
ASSERT(track >= 0);
|
||||
|
||||
// First, check if it is already assigned
|
||||
for (int i = 0; i < CacheMax; i++) {
|
||||
if (cache[i].disktrk) {
|
||||
if (cache[i].disktrk->GetTrack() == track) {
|
||||
// Track match
|
||||
cache[i].serial = serial;
|
||||
return cache[i].disktrk;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Next, check for empty
|
||||
for (int i = 0; i < CacheMax; i++) {
|
||||
if (!cache[i].disktrk) {
|
||||
// Try loading
|
||||
if (Load(i, track)) {
|
||||
// Success loading
|
||||
cache[i].serial = serial;
|
||||
return cache[i].disktrk;
|
||||
}
|
||||
|
||||
// Load failed
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, find the youngest serial number and delete it
|
||||
|
||||
// Set index 0 as candidate c
|
||||
DWORD s = cache[0].serial;
|
||||
int c = 0;
|
||||
|
||||
// Compare candidate with serial and update to smaller one
|
||||
for (int i = 0; i < CacheMax; i++) {
|
||||
ASSERT(cache[i].disktrk);
|
||||
|
||||
// Compare and update the existing serial
|
||||
if (cache[i].serial < s) {
|
||||
s = cache[i].serial;
|
||||
c = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Save this track
|
||||
if (!cache[c].disktrk->Save(sec_path)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Delete this track
|
||||
DiskTrack *disktrk = cache[c].disktrk;
|
||||
cache[c].disktrk = NULL;
|
||||
|
||||
if (Load(c, track, disktrk)) {
|
||||
// Successful loading
|
||||
cache[c].serial = serial;
|
||||
return cache[c].disktrk;
|
||||
}
|
||||
|
||||
// Load failed
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Load cache
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool DiskCache::Load(int index, int track, DiskTrack *disktrk)
|
||||
{
|
||||
ASSERT((index >= 0) && (index < CacheMax));
|
||||
ASSERT(track >= 0);
|
||||
ASSERT(!cache[index].disktrk);
|
||||
|
||||
// Get the number of sectors on this track
|
||||
int sectors = sec_blocks - (track << 8);
|
||||
ASSERT(sectors > 0);
|
||||
if (sectors > 0x100) {
|
||||
sectors = 0x100;
|
||||
}
|
||||
|
||||
// Create a disk track
|
||||
if (disktrk == NULL) {
|
||||
disktrk = new DiskTrack();
|
||||
}
|
||||
|
||||
// Initialize disk track
|
||||
disktrk->Init(track, sec_size, sectors, cd_raw, imgoffset);
|
||||
|
||||
// Try loading
|
||||
if (!disktrk->Load(sec_path)) {
|
||||
// Failure
|
||||
delete disktrk;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocation successful, work set
|
||||
cache[index].disktrk = disktrk;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DiskCache::UpdateSerialNumber()
|
||||
{
|
||||
// Update and do nothing except 0
|
||||
serial++;
|
||||
if (serial != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear serial of all caches (loop in 32bit)
|
||||
for (int i = 0; i < CacheMax; i++) {
|
||||
cache[i].serial = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// X68000 EMULATOR "XM6"
|
||||
//
|
||||
// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp)
|
||||
// Copyright (C) 2014-2020 GIMONS
|
||||
//
|
||||
// XM6i
|
||||
// Copyright (C) 2010-2015 isaki@NetBSD.org
|
||||
//
|
||||
// Imported sava's Anex86/T98Next image and MO format support patch.
|
||||
// Comments translated to english by akuker.
|
||||
//
|
||||
// [ DiskTrack and DiskCache ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../rascsi.h"
|
||||
#include "filepath.h"
|
||||
#include "file_access/file_access.h"
|
||||
|
||||
// Number of tracks to cache
|
||||
#define CacheMax 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
|
||||
} dt;
|
||||
|
||||
public:
|
||||
DiskTrack();
|
||||
~DiskTrack();
|
||||
|
||||
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);
|
||||
|
||||
// Read / Write
|
||||
bool ReadSector(BYTE *buf, int sec) const; // Sector Read
|
||||
bool WriteSector(const BYTE *buf, int sec); // Sector Write
|
||||
|
||||
int GetTrack() const { return dt.track; } // Get track
|
||||
};
|
||||
|
||||
class DiskCache : public FileAccess
|
||||
{
|
||||
public:
|
||||
// Internal data definition
|
||||
typedef struct {
|
||||
DiskTrack *disktrk; // Disk Track
|
||||
DWORD serial; // Serial
|
||||
} cache_t;
|
||||
|
||||
public:
|
||||
DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgoff = 0);
|
||||
~DiskCache();
|
||||
|
||||
// Access
|
||||
bool Save() override; // Save and release all
|
||||
bool ReadSector(BYTE *buf, int block) override; // Sector Read
|
||||
bool WriteSector(const BYTE *buf, int block) override; // Sector Write
|
||||
bool GetCache(int index, int& track, DWORD& serial) const override; // Get cache information
|
||||
|
||||
private:
|
||||
// Internal Management
|
||||
void Clear(); // Clear all tracks
|
||||
DiskTrack* Assign(int track); // Load track
|
||||
bool Load(int index, int track, DiskTrack *disktrk = NULL); // Load track
|
||||
void UpdateSerialNumber(); // Update serial number
|
||||
|
||||
// Internal data
|
||||
cache_t cache[CacheMax]; // Cache management
|
||||
};
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
#include "file_access.h"
|
||||
|
||||
FileAccess::FileAccess(const Filepath& path, int size, uint32_t blocks, off_t imgoff){
|
||||
|
||||
serial = 0;
|
||||
sec_path = path;
|
||||
sec_size = size;
|
||||
sec_blocks = blocks;
|
||||
imgoffset = imgoff;
|
||||
}
|
||||
FileAccess::~FileAccess(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
off_t FileAccess::GetSectorOffset(int block){
|
||||
|
||||
int sector_num = block & 0xff;
|
||||
return (off_t)sector_num << sec_size;
|
||||
}
|
||||
|
||||
off_t FileAccess::GetTrackOffset(int block){
|
||||
|
||||
// Assuming that all tracks hold 256 sectors
|
||||
int track_num = block >> 8;
|
||||
|
||||
// Calculate offset (previous tracks are considered to hold 256 sectors)
|
||||
off_t offset = ((off_t)track_num << 8);
|
||||
if (cd_raw) {
|
||||
ASSERT(sec_size == 11);
|
||||
offset *= 0x930;
|
||||
offset += 0x10;
|
||||
} else {
|
||||
offset <<= sec_size;
|
||||
}
|
||||
|
||||
// Add offset to real image
|
||||
offset += imgoffset;
|
||||
|
||||
return offset;
|
||||
}
|
|
@ -20,43 +20,30 @@
|
|||
#include "../rascsi.h"
|
||||
#include "filepath.h"
|
||||
|
||||
class DiskCache
|
||||
class FileAccess
|
||||
{
|
||||
|
||||
public:
|
||||
DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgoff = 0);
|
||||
~DiskCache();
|
||||
FileAccess(const Filepath& path, int size, uint32_t blocks, off_t imgoff = 0);
|
||||
virtual ~FileAccess();
|
||||
|
||||
void SetRawMode(BOOL raw); // CD-ROM raw mode setting
|
||||
void SetRawMode(bool raw) { cd_raw = raw; }; // 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 GetCache(int index, int& track, DWORD& serial) const; // Get cache information
|
||||
virtual bool Save() = 0; // Save and release all
|
||||
virtual bool ReadSector(BYTE *buf, int block) = 0; // Sector Read
|
||||
virtual bool WriteSector(const BYTE *buf, int block) = 0; // Sector Write
|
||||
virtual bool GetCache(int index, int& track, DWORD& serial) const = 0; // Get cache information
|
||||
|
||||
private:
|
||||
// Internal Management
|
||||
// void Clear(); // Clear all tracks
|
||||
// DiskTrack* Assign(int track); // Load track
|
||||
// bool Load(int index, int track, DiskTrack *disktrk = NULL); // Load track
|
||||
// void UpdateSerialNumber(); // Update serial number
|
||||
|
||||
// Internal data
|
||||
// cache_t cache[CacheMax]; // Cache management
|
||||
protected:
|
||||
bool cd_raw = false;
|
||||
DWORD serial; // 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
|
||||
off_t imgoffset; // Offset to actual data
|
||||
|
||||
bool initialized;
|
||||
|
||||
const char *memory_block;
|
||||
struct stat sb;
|
||||
int fd;
|
||||
|
||||
|
||||
off_t GetTrackOffset(int block);
|
||||
off_t GetSectorOffset(int block);
|
||||
};
|
|
@ -0,0 +1,49 @@
|
|||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// X68000 EMULATOR "XM6"
|
||||
//
|
||||
// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp)
|
||||
// Copyright (C) 2014-2020 GIMONS
|
||||
//
|
||||
// XM6i
|
||||
// Copyright (C) 2010-2015 isaki@NetBSD.org
|
||||
//
|
||||
// Imported sava's Anex86/T98Next image and MO format support patch.
|
||||
// Comments translated to english by akuker.
|
||||
//
|
||||
// [ DiskTrack and DiskCache ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "file_access/file_access_factory.h"
|
||||
#include "log.h"
|
||||
#include "file_access/disk_track_cache.h"
|
||||
#include "file_access/mmap_file_access.h"
|
||||
#include "file_access/posix_file_access.h"
|
||||
|
||||
FileAccessType FileAccessFactory::current_access_type = FileAccessType::ePosixFile;
|
||||
|
||||
FileAccess *FileAccessFactory::CreateFileAccess(const Filepath& path, int size, uint32_t blocks, off_t imgoff){
|
||||
|
||||
FileAccess *result = NULL;
|
||||
|
||||
if (current_access_type == FileAccessType::eMmapFile){
|
||||
LOGINFO("%s Creating MmapFileAccess %s", __PRETTY_FUNCTION__, path.GetPath())
|
||||
result = new MmapFileAccess(path, size, blocks, imgoff);
|
||||
}
|
||||
else if(current_access_type == FileAccessType::eRamCache) {
|
||||
LOGINFO("%s Creating DiskCache %s", __PRETTY_FUNCTION__, path.GetPath())
|
||||
result = new DiskCache(path, size, blocks, imgoff);
|
||||
}
|
||||
else if(current_access_type == FileAccessType::ePosixFile) {
|
||||
LOGINFO("%s Creating PosixFileAccess %s", __PRETTY_FUNCTION__, path.GetPath())
|
||||
result = new PosixFileAccess(path, size, blocks, imgoff);
|
||||
}
|
||||
|
||||
if (result == NULL){
|
||||
LOGWARN("%s Unable to create the File Access", __PRETTY_FUNCTION__);
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// X68000 EMULATOR "XM6"
|
||||
//
|
||||
// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp)
|
||||
// Copyright (C) 2014-2020 GIMONS
|
||||
//
|
||||
// XM6i
|
||||
// Copyright (C) 2010-2015 isaki@NetBSD.org
|
||||
//
|
||||
// Imported sava's Anex86/T98Next image and MO format support patch.
|
||||
// Comments translated to english by akuker.
|
||||
//
|
||||
// [ DiskTrack and DiskCache ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "file_access/file_access.h"
|
||||
|
||||
enum FileAccessType {
|
||||
eRamCache,
|
||||
eMmapFile,
|
||||
ePosixFile,
|
||||
};
|
||||
|
||||
class FileAccessFactory
|
||||
{
|
||||
public:
|
||||
static void SetFileAccessMethod(FileAccessType method) { current_access_type = method; };
|
||||
static FileAccessType GetFileAccessMethod() { return current_access_type; };
|
||||
|
||||
static FileAccess *CreateFileAccess(const Filepath& path, int size, uint32_t blocks, off_t imgoff = 0);
|
||||
|
||||
private:
|
||||
static FileAccessType current_access_type;
|
||||
};
|
|
@ -0,0 +1,101 @@
|
|||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
// This method of file access will use the mmap() capabilities to 'map' the
|
||||
// file into memory.
|
||||
//
|
||||
// This doesn't actually copy the file into RAM, but instead maps the file
|
||||
// as virtual memory. Behind the scenes, the file is still being accessed.
|
||||
//
|
||||
// The operating system will do some caching of the data to prevent direct
|
||||
// drive access for each read/write. So, instead of implementing our own
|
||||
// caching mechanism (like in disk_track_cache.h), we just rely on the
|
||||
// operating system.
|
||||
//
|
||||
// [ MmapFileAccess ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "mmap_file_access.h"
|
||||
#include "log.h"
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Direct file access that will map the file into virtual memory space
|
||||
//
|
||||
//===========================================================================
|
||||
MmapFileAccess::MmapFileAccess(const Filepath& path, int size, uint32_t blocks, off_t imgoff) : FileAccess(path, size, blocks, imgoff)
|
||||
{
|
||||
ASSERT(blocks > 0);
|
||||
ASSERT(imgoff >= 0);
|
||||
|
||||
fd = open(path.GetPath(), O_RDWR);
|
||||
if(fd < 0){
|
||||
LOGWARN("Unable to open file %s. Errno:%d", path.GetPath(), errno)
|
||||
}
|
||||
LOGWARN("%s opened %s", __PRETTY_FUNCTION__, path.GetPath());
|
||||
struct stat sb;
|
||||
if(fstat(fd, &sb) < 0){
|
||||
LOGWARN("Unable to run fstat. Errno:%d", errno);
|
||||
}
|
||||
printf("Size: %llu\n", (uint64_t)sb.st_size);
|
||||
|
||||
LOGWARN("%s mmap-ed file of size: %llu", __PRETTY_FUNCTION__, (uint64_t)sb.st_size);
|
||||
|
||||
// int x = EACCES;
|
||||
|
||||
memory_block = (const char*)mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
int errno_val = errno;
|
||||
if (memory_block == MAP_FAILED) {
|
||||
LOGWARN("Unabled to memory map file %s", path.GetPath());
|
||||
LOGWARN(" Errno:%d", errno_val);
|
||||
return;
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
MmapFileAccess::~MmapFileAccess()
|
||||
{
|
||||
munmap((void*)memory_block, sb.st_size);
|
||||
close(fd);
|
||||
|
||||
// Force the OS to save any cached data to the disk
|
||||
sync();
|
||||
}
|
||||
|
||||
bool MmapFileAccess::ReadSector(BYTE *buf, int block)
|
||||
{
|
||||
ASSERT(sec_size != 0);
|
||||
ASSERT(buf);
|
||||
ASSERT(block < sec_blocks);
|
||||
ASSERT(memory_block);
|
||||
|
||||
int sector_size_bytes = (off_t)1 << sec_size;
|
||||
|
||||
// Calculate offset into the image file
|
||||
off_t offset = GetTrackOffset(block);
|
||||
offset += GetSectorOffset(block);
|
||||
|
||||
memcpy(buf, &memory_block[offset], sector_size_bytes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MmapFileAccess::WriteSector(const BYTE *buf, int block)
|
||||
{
|
||||
|
||||
ASSERT(buf);
|
||||
ASSERT(block < sec_blocks);
|
||||
ASSERT(memory_block);
|
||||
|
||||
ASSERT((block * sec_size) <= (sb.st_size + sec_size));
|
||||
|
||||
memcpy((void*)&memory_block[(block * sec_size)], buf, sec_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI (*^..^*)
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
// This method of file access will use the mmap() capabilities to 'map' the
|
||||
// file into memory.
|
||||
//
|
||||
// This doesn't actually copy the file into RAM, but instead maps the file
|
||||
// as virtual memory. Behind the scenes, the file is still being accessed.
|
||||
//
|
||||
// The operating system will do some caching of the data to prevent direct
|
||||
// drive access for each read/write. So, instead of implementing our own
|
||||
// caching mechanism (like in disk_track_cache.h), we just rely on the
|
||||
// operating system.
|
||||
//
|
||||
// [ MmapFileAccess ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../rascsi.h"
|
||||
#include "filepath.h"
|
||||
#include "file_access/file_access.h"
|
||||
|
||||
class MmapFileAccess : public FileAccess
|
||||
{
|
||||
|
||||
public:
|
||||
MmapFileAccess(const Filepath& path, int size, uint32_t blocks, off_t imgoff = 0);
|
||||
~MmapFileAccess();
|
||||
|
||||
void SetRawMode(BOOL raw); // CD-ROM raw mode setting
|
||||
|
||||
// Access
|
||||
bool Save() { return true; }; // Save and release all
|
||||
bool ReadSector(BYTE *buf, int block); // Sector Read
|
||||
bool WriteSector(const BYTE *buf, int block); // Sector Write
|
||||
bool GetCache(int index, int& track, DWORD& serial) const { return true; }; // Get cache information
|
||||
|
||||
|
||||
private:
|
||||
const char *memory_block;
|
||||
struct stat sb;
|
||||
int fd;
|
||||
|
||||
bool initialized = false;
|
||||
};
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI (*^..^*)
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2021 akuker
|
||||
//
|
||||
// [ PosixFileAccess ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "posix_file_access.h"
|
||||
#include "log.h"
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Direct file access that will map the file into virtual memory space
|
||||
//
|
||||
//===========================================================================
|
||||
PosixFileAccess::PosixFileAccess(const Filepath& path, int size, uint32_t blocks, off_t imgoff) : FileAccess(path, size, blocks, imgoff)
|
||||
{
|
||||
ASSERT(blocks > 0);
|
||||
ASSERT(imgoff >= 0);
|
||||
|
||||
|
||||
fd = open(path.GetPath(), O_RDWR);
|
||||
if(fd < 0){
|
||||
LOGWARN("Unable to open file %s. Errno:%d", path.GetPath(), errno)
|
||||
return;
|
||||
}
|
||||
struct stat sb;
|
||||
if(fstat(fd, &sb) < 0){
|
||||
LOGWARN("Unable to run fstat. Errno:%d", errno);
|
||||
return;
|
||||
}
|
||||
|
||||
LOGWARN("%s opened file of size: %llu", __PRETTY_FUNCTION__, (uint64_t)sb.st_size);
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
PosixFileAccess::~PosixFileAccess()
|
||||
{
|
||||
close(fd);
|
||||
|
||||
// Force the OS to save any cached data to the disk
|
||||
sync();
|
||||
}
|
||||
|
||||
bool PosixFileAccess::ReadSector(BYTE *buf, int block)
|
||||
{
|
||||
if(!initialized){
|
||||
return false;
|
||||
}
|
||||
|
||||
ASSERT(sec_size != 0);
|
||||
ASSERT(buf);
|
||||
ASSERT(block < sec_blocks);
|
||||
ASSERT(memory_block);
|
||||
|
||||
size_t sector_size_bytes = (size_t)1 << sec_size;
|
||||
|
||||
// Calculate offset into the image file
|
||||
off_t offset = GetTrackOffset(block);
|
||||
offset += GetSectorOffset(block);
|
||||
|
||||
lseek(fd, offset, SEEK_SET);
|
||||
size_t result = read(fd, buf,sector_size_bytes);
|
||||
if(result != sector_size_bytes){
|
||||
LOGWARN("%s only read %d bytes but wanted %d ", __PRETTY_FUNCTION__, result, sector_size_bytes);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PosixFileAccess::WriteSector(const BYTE *buf, int block)
|
||||
{
|
||||
if(!initialized){
|
||||
return false;
|
||||
}
|
||||
|
||||
ASSERT(buf);
|
||||
ASSERT(block < sec_blocks);
|
||||
ASSERT(memory_block);
|
||||
|
||||
ASSERT((block * sec_size) <= (sb.st_size + sec_size));
|
||||
|
||||
size_t sector_size_bytes = (size_t)1 << sec_size;
|
||||
|
||||
off_t offset = GetTrackOffset(block);
|
||||
offset += GetSectorOffset(block);
|
||||
|
||||
|
||||
lseek(fd, offset, SEEK_SET);
|
||||
size_t result = write(fd, buf,sector_size_bytes);
|
||||
if(result != sector_size_bytes){
|
||||
LOGWARN("%s only wrote %d bytes but wanted %d ", __PRETTY_FUNCTION__, result, sector_size_bytes);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI (*^..^*)
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2021 akuker
|
||||
//
|
||||
// [ PosixFileAccess ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "filepath.h"
|
||||
#include "file_access/file_access.h"
|
||||
|
||||
class PosixFileAccess : public FileAccess
|
||||
{
|
||||
|
||||
public:
|
||||
PosixFileAccess(const Filepath& path, int size, uint32_t blocks, off_t imgoff = 0);
|
||||
~PosixFileAccess();
|
||||
|
||||
void SetRawMode(BOOL raw); // CD-ROM raw mode setting
|
||||
|
||||
// Access
|
||||
bool Save() { return true; }; // Save and release all
|
||||
bool ReadSector(BYTE *buf, int block); // Sector Read
|
||||
bool WriteSector(const BYTE *buf, int block); // Sector Write
|
||||
bool GetCache(int index, int& track, DWORD& serial) const { return true; }; // Get cache information
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
int fd;
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
};
|
||||
|
Loading…
Reference in New Issue