RASCSI/src/x68k/RASDRV/BRIDGE.C
Daniel Markstedt af4e3dfe80
Translate source code in x68k (#289)
* Translate code comments

* Remove documentation that is contained in wiki

* Translate code comments

* Remove documentation that is contained in wiki

* Translate configuration file

* Remove documentation that is covered by wiki

* Translate code comments

* Translate strings and code comments

* Cleanup
2021-10-01 15:23:53 -05:00

2431 lines
52 KiB
C

//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2017 GIMONS
// [ Host Filesystem Bridge Driver ]
//
//---------------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include <sys/dos.h>
#include <sys/scsi.h>
#include <iocslib.h>
#include "bridge.h"
//---------------------------------------------------------------------------
//
// Variable definitions
//
//---------------------------------------------------------------------------
volatile BYTE *request; // Request header address
DWORD command; // Command number
DWORD unit; // Unit number
//===========================================================================
//
/// File system (SCSI integration)
//
//===========================================================================
typedef struct
{
char DeviceType;
char RMB;
char ANSI_Ver;
char RDF;
char AddLen;
char RESV0;
char RESV1;
char OptFunc;
char VendorID[8];
char ProductID[16];
char FirmRev[4];
} INQUIRY_T;
int scsiid; // SCSI ID
//---------------------------------------------------------------------------
//
// Initialize
//
//---------------------------------------------------------------------------
BOOL SCSI_Init(void)
{
int i;
INQUIRY_T inq;
// SCSI ID not set
scsiid = -1;
for (i = 0; i <= 7; i++) {
if (S_INQUIRY(sizeof(INQUIRY_T) , i, (struct INQUIRY*)&inq) < 0) {
continue;
}
if (memcmp(&(inq.ProductID), "RASCSI BRIDGE", 13) != 0) {
continue;
}
// SCSI ID set
scsiid = i;
return TRUE;
}
return FALSE;
}
//---------------------------------------------------------------------------
//
// Send commands
//
//---------------------------------------------------------------------------
int SCSI_SendCmd(BYTE *buf, int len)
{
int ret;
BYTE cmdbuf[10];
BYTE sts;
BYTE msg;
BYTE retbuf[4];
ret = FS_FATAL_MEDIAOFFLINE;
cmdbuf[0] = 0x2a;
cmdbuf[1] = 0;
cmdbuf[2] = 2;
cmdbuf[3] = command;
cmdbuf[4] = 0;
cmdbuf[5] = 0;
cmdbuf[6] = (BYTE)(len >> 16);
cmdbuf[7] = (BYTE)(len >> 8);
cmdbuf[8] = (BYTE)len;
cmdbuf[9] = 0;
// Retry when select times out
if (S_SELECT(scsiid) != 0) {
S_RESET();
if (S_SELECT(scsiid) != 0) {
return ret;
}
}
if (S_CMDOUT(10, cmdbuf) != 0) {
return ret;
}
if (S_DATAOUT_P(len, buf) != 0) {
return ret;
}
if (S_STSIN(&sts) != 0) {
return ret;
}
if (S_MSGIN(&msg) != 0) {
return ret;
}
cmdbuf[0] = 0x28;
cmdbuf[1] = 0;
cmdbuf[2] = 2;
cmdbuf[3] = command;
cmdbuf[4] = 0;
cmdbuf[5] = 0;
cmdbuf[6] = 0;
cmdbuf[7] = 0;
cmdbuf[8] = 4;
cmdbuf[9] = 0;
// Retry when select times out
if (S_SELECT(scsiid) != 0) {
S_RESET();
if (S_SELECT(scsiid) != 0) {
return ret;
}
}
if (S_CMDOUT(10, cmdbuf) != 0) {
return ret;
}
if (S_DATAIN_P(4, retbuf) != 0) {
return ret;
}
if (S_STSIN(&sts) != 0) {
return ret;
}
if (S_MSGIN(&msg) != 0) {
return ret;
}
ret = *(int*)retbuf;
return ret;
}
//---------------------------------------------------------------------------
//
// Call commands
//
//---------------------------------------------------------------------------
int SCSI_CalCmd(BYTE *buf, int len, BYTE *outbuf, int outlen)
{
int ret;
BYTE cmdbuf[10];
BYTE sts;
BYTE msg;
BYTE retbuf[4];
ret = FS_FATAL_MEDIAOFFLINE;
cmdbuf[0] = 0x2a;
cmdbuf[1] = 0;
cmdbuf[2] = 2;
cmdbuf[3] = command;
cmdbuf[4] = 0;
cmdbuf[5] = 0;
cmdbuf[6] = (BYTE)(len >> 16);
cmdbuf[7] = (BYTE)(len >> 8);
cmdbuf[8] = (BYTE)len;
cmdbuf[9] = 0;
// Retry when select times out
if (S_SELECT(scsiid) != 0) {
S_RESET();
if (S_SELECT(scsiid) != 0) {
return ret;
}
}
if (S_CMDOUT(10, cmdbuf) != 0) {
return ret;
}
if (S_DATAOUT_P(len, buf) != 0) {
return ret;
}
if (S_STSIN(&sts) != 0) {
return ret;
}
if (S_MSGIN(&msg) != 0) {
return ret;
}
cmdbuf[0] = 0x28;
cmdbuf[1] = 0;
cmdbuf[2] = 2;
cmdbuf[3] = command;
cmdbuf[4] = 0;
cmdbuf[5] = 0;
cmdbuf[6] = 0;
cmdbuf[7] = 0;
cmdbuf[8] = 4;
cmdbuf[9] = 0;
// Retry when select times out
if (S_SELECT(scsiid) != 0) {
S_RESET();
if (S_SELECT(scsiid) != 0) {
return ret;
}
}
if (S_CMDOUT(10, cmdbuf) != 0) {
return ret;
}
if (S_DATAIN_P(4, retbuf) != 0) {
return ret;
}
if (S_STSIN(&sts) != 0) {
return ret;
}
if (S_MSGIN(&msg) != 0) {
return ret;
}
// Stop receiving return data on error
ret = *(int*)retbuf;
if (ret < 0) {
return ret;
}
cmdbuf[0] = 0x28;
cmdbuf[1] = 0;
cmdbuf[2] = 2;
cmdbuf[3] = command;
cmdbuf[4] = 0;
cmdbuf[5] = 0;
cmdbuf[6] = (BYTE)(outlen >> 16);
cmdbuf[7] = (BYTE)(outlen >> 8);
cmdbuf[8] = (BYTE)outlen;
cmdbuf[9] = 1;
// Retry when select times out
if (S_SELECT(scsiid) != 0) {
S_RESET();
if (S_SELECT(scsiid) != 0) {
return ret;
}
}
if (S_CMDOUT(10, cmdbuf) != 0) {
return ret;
}
if (S_DATAIN_P(outlen, outbuf) != 0) {
return ret;
}
if (S_STSIN(&sts) != 0) {
return ret;
}
if (S_MSGIN(&msg) != 0) {
return ret;
}
ret = *(int*)retbuf;
return ret;
}
//---------------------------------------------------------------------------
//
// Get option data
//
//---------------------------------------------------------------------------
BOOL SCSI_ReadOpt(BYTE *buf, int len)
{
BYTE cmdbuf[10];
BYTE sts;
BYTE msg;
cmdbuf[0] = 0x28;
cmdbuf[1] = 0;
cmdbuf[2] = 2;
cmdbuf[3] = command;
cmdbuf[4] = 0;
cmdbuf[5] = 0;
cmdbuf[6] = (BYTE)(len >> 16);
cmdbuf[7] = (BYTE)(len >> 8);
cmdbuf[8] = (BYTE)len;
cmdbuf[9] = 2;
// Retry when select times out
if (S_SELECT(scsiid) != 0) {
S_RESET();
if (S_SELECT(scsiid) != 0) {
return FALSE;
}
}
if (S_CMDOUT(10, cmdbuf) != 0) {
return FALSE;
}
if (S_DATAIN_P(len, buf) != 0) {
return FALSE;
}
if (S_STSIN(&sts) != 0) {
return FALSE;
}
if (S_MSGIN(&msg) != 0) {
return FALSE;
}
return TRUE;
}
//---------------------------------------------------------------------------
//
// Write option data
//
//---------------------------------------------------------------------------
BOOL SCSI_WriteOpt(BYTE *buf, int len)
{
BYTE cmdbuf[10];
BYTE sts;
BYTE msg;
cmdbuf[0] = 0x2a;
cmdbuf[1] = 0;
cmdbuf[2] = 2;
cmdbuf[3] = command;
cmdbuf[4] = 0;
cmdbuf[5] = 0;
cmdbuf[6] = (BYTE)(len >> 16);
cmdbuf[7] = (BYTE)(len >> 8);
cmdbuf[8] = (BYTE)len;
cmdbuf[9] = 1;
// Retry when select times out
if (S_SELECT(scsiid) != 0) {
S_RESET();
if (S_SELECT(scsiid) != 0) {
return FALSE;
}
}
if (S_CMDOUT(10, cmdbuf) != 0) {
return FALSE;
}
if (S_DATAOUT_P(len, buf) != 0) {
return FALSE;
}
if (S_STSIN(&sts) != 0) {
return FALSE;
}
if (S_MSGIN(&msg) != 0) {
return FALSE;
}
return TRUE;
}
//===========================================================================
//
/// File System
//
//===========================================================================
//---------------------------------------------------------------------------
//
// $40 - Device startup
//
//---------------------------------------------------------------------------
DWORD FS_InitDevice(const argument_t* pArgument)
{
return (DWORD)SCSI_SendCmd((BYTE*)pArgument, sizeof(argument_t));
}
//---------------------------------------------------------------------------
//
// $41 - Directory check
//
//---------------------------------------------------------------------------
int FS_CheckDir(const namests_t* pNamests)
{
BYTE buf[256];
DWORD *dp;
int i;
i = 0;
dp = (DWORD*)buf;
*dp = unit;
i += sizeof(DWORD);
memcpy(&buf[i], pNamests, sizeof(namests_t));
i += sizeof(namests_t);
return SCSI_SendCmd(buf, i);
}
//---------------------------------------------------------------------------
//
// $42 - Create directory
//
//---------------------------------------------------------------------------
int FS_MakeDir(const namests_t* pNamests)
{
BYTE buf[256];
DWORD *dp;
int i;
i = 0;
dp = (DWORD*)buf;
*dp = unit;
i += sizeof(DWORD);
memcpy(&buf[i], pNamests, sizeof(namests_t));
i += sizeof(namests_t);
return SCSI_SendCmd(buf, i);
}
//---------------------------------------------------------------------------
//
// $43 - Delete directory
//
//---------------------------------------------------------------------------
int FS_RemoveDir(const namests_t* pNamests)
{
BYTE buf[256];
DWORD *dp;
int i;
i = 0;
dp = (DWORD*)buf;
*dp = unit;
i += sizeof(DWORD);
memcpy(&buf[i], pNamests, sizeof(namests_t));
i += sizeof(namests_t);
return SCSI_SendCmd(buf, i);
}
//---------------------------------------------------------------------------
//
// $44 - Change file name
//
//---------------------------------------------------------------------------
int FS_Rename(const namests_t* pNamests, const namests_t* pNamestsNew)
{
BYTE buf[256];
DWORD *dp;
int i;
i = 0;
dp = (DWORD*)buf;
*dp = unit;
i += sizeof(DWORD);
memcpy(&buf[i], pNamests, sizeof(namests_t));
i += sizeof(namests_t);
memcpy(&buf[i], pNamestsNew, sizeof(namests_t));
i += sizeof(namests_t);
return SCSI_SendCmd(buf, i);
}
//---------------------------------------------------------------------------
//
// $45 - Delete file
//
//---------------------------------------------------------------------------
int FS_Delete(const namests_t* pNamests)
{
BYTE buf[256];
DWORD *dp;
int i;
i = 0;
dp = (DWORD*)buf;
*dp = unit;
i += sizeof(DWORD);
memcpy(&buf[i], pNamests, sizeof(namests_t));
i += sizeof(namests_t);
return SCSI_SendCmd(buf, i);
}
//---------------------------------------------------------------------------
//
// $46 - Get/set file attribute
//
//---------------------------------------------------------------------------
int FS_Attribute(const namests_t* pNamests, DWORD nHumanAttribute)
{
BYTE buf[256];
DWORD *dp;
int i;
i = 0;
dp = (DWORD*)buf;
*dp = unit;
i += sizeof(DWORD);
memcpy(&buf[i], pNamests, sizeof(namests_t));
i += sizeof(namests_t);
dp = (DWORD*)&buf[i];
*dp = nHumanAttribute;
i += sizeof(DWORD);
return SCSI_SendCmd(buf, i);
}
//---------------------------------------------------------------------------
//
// $47 - File search
//
//---------------------------------------------------------------------------
int FS_Files(DWORD nKey,
const namests_t* pNamests, files_t* info)
{
BYTE buf[256];
DWORD *dp;
int i;
i = 0;
dp = (DWORD*)buf;
*dp = unit;
i += sizeof(DWORD);
dp = (DWORD*)&buf[i];
*dp = nKey;
i += sizeof(DWORD);
memcpy(&buf[i], pNamests, sizeof(namests_t));
i += sizeof(namests_t);
memcpy(&buf[i], info, sizeof(files_t));
i += sizeof(files_t);
return SCSI_CalCmd(buf, i, (BYTE*)info, sizeof(files_t));
}
//---------------------------------------------------------------------------
//
// $48 - Search next file
//
//---------------------------------------------------------------------------
int FS_NFiles(DWORD nKey, files_t* info)
{
BYTE buf[256];
DWORD *dp;
int i;
i = 0;
dp = (DWORD*)buf;
*dp = unit;
i += sizeof(DWORD);
dp = (DWORD*)&buf[i];
*dp = nKey;
i += sizeof(DWORD);
memcpy(&buf[i], info, sizeof(files_t));
i += sizeof(files_t);
return SCSI_CalCmd(buf, i, (BYTE*)info, sizeof(files_t));
}
//---------------------------------------------------------------------------
//
// $49 - Create new file
//
//---------------------------------------------------------------------------
int FS_Create(DWORD nKey,
const namests_t* pNamests, fcb_t* pFcb, DWORD nAttribute, BOOL bForce)
{
BYTE buf[256];
DWORD *dp;
BOOL *bp;
int i;
i = 0;
dp = (DWORD*)buf;
*dp = unit;
i += sizeof(DWORD);
dp = (DWORD*)&buf[i];
*dp = nKey;
i += sizeof(DWORD);
memcpy(&buf[i], pNamests, sizeof(namests_t));
i += sizeof(namests_t);
memcpy(&buf[i], pFcb, sizeof(fcb_t));
i += sizeof(fcb_t);
dp = (DWORD*)&buf[i];
*dp = nAttribute;
i += sizeof(DWORD);
bp = (BOOL*)&buf[i];
*bp = bForce;
i += sizeof(BOOL);
return SCSI_CalCmd(buf, i, (BYTE*)pFcb, sizeof(fcb_t));
}
//---------------------------------------------------------------------------
//
// $4A - File open
//
//---------------------------------------------------------------------------
int FS_Open(DWORD nKey,
const namests_t* pNamests, fcb_t* pFcb)
{
BYTE buf[256];
DWORD *dp;
int i;
i = 0;
dp = (DWORD*)buf;
*dp = unit;
i += sizeof(DWORD);
dp = (DWORD*)&buf[i];
*dp = nKey;
i += sizeof(DWORD);
memcpy(&buf[i], pNamests, sizeof(namests_t));
i += sizeof(namests_t);
memcpy(&buf[i], pFcb, sizeof(fcb_t));
i += sizeof(fcb_t);
return SCSI_CalCmd(buf, i, (BYTE*)pFcb, sizeof(fcb_t));
}
//---------------------------------------------------------------------------
//
// $4B - File close
//
//---------------------------------------------------------------------------
int FS_Close(DWORD nKey, fcb_t* pFcb)
{
BYTE buf[256];
DWORD *dp;
int i;
i = 0;
dp = (DWORD*)buf;
*dp = unit;
i += sizeof(DWORD);
dp = (DWORD*)&buf[i];
*dp = nKey;
i += sizeof(DWORD);
memcpy(&buf[i], pFcb, sizeof(fcb_t));
i += sizeof(fcb_t);
return SCSI_CalCmd(buf, i, (BYTE*)pFcb, sizeof(fcb_t));
}
//---------------------------------------------------------------------------
//
// $4C - Read file
//
//---------------------------------------------------------------------------
int FS_Read(DWORD nKey, fcb_t* pFcb, BYTE* pAddress, DWORD nSize)
{
BYTE buf[256];
DWORD *dp;
int i;
int nResult;
i = 0;
dp = (DWORD*)buf;
*dp = nKey;
i += sizeof(DWORD);
memcpy(&buf[i], pFcb, sizeof(fcb_t));
i += sizeof(fcb_t);
dp = (DWORD*)&buf[i];
*dp = nSize;
i += sizeof(DWORD);
nResult = SCSI_CalCmd(buf, i, (BYTE*)pFcb, sizeof(fcb_t));
if (nResult > 0) {
SCSI_ReadOpt(pAddress, nResult);
}
return nResult;
}
//---------------------------------------------------------------------------
//
// $4D - Write file
//
//---------------------------------------------------------------------------
int FS_Write(DWORD nKey, fcb_t* pFcb, BYTE* pAddress, DWORD nSize)
{
BYTE buf[256];
DWORD *dp;
int i;
i = 0;
dp = (DWORD*)buf;
*dp = nKey;
i += sizeof(DWORD);
memcpy(&buf[i], pFcb, sizeof(fcb_t));
i += sizeof(fcb_t);
dp = (DWORD*)&buf[i];
*dp = nSize;
i += sizeof(DWORD);
if (nSize != 0) {
if (!SCSI_WriteOpt(pAddress, nSize)) {
return FS_FATAL_MEDIAOFFLINE;
}
}
return SCSI_SendCmd(buf, i);
}
//---------------------------------------------------------------------------
//
// $4E - File seek
//
//---------------------------------------------------------------------------
int FS_Seek(DWORD nKey, fcb_t* pFcb, DWORD nMode, int nOffset)
{
BYTE buf[256];
DWORD *dp;
int i;
i = 0;
dp = (DWORD*)buf;
*dp = nKey;
i += sizeof(DWORD);
memcpy(&buf[i], pFcb, sizeof(fcb_t));
i += sizeof(fcb_t);
dp = (DWORD*)&buf[i];
*dp = nMode;
i += sizeof(DWORD);
dp = (DWORD*)&buf[i];
*dp = nOffset;
i += sizeof(int);
return SCSI_CalCmd(buf, i, (BYTE*)pFcb, sizeof(fcb_t));
}
//---------------------------------------------------------------------------
//
// $4F - Get/set file time stamp
//
//---------------------------------------------------------------------------
DWORD FS_TimeStamp(DWORD nKey,
fcb_t* pFcb, DWORD nHumanTime)
{
BYTE buf[256];
DWORD *dp;
int i;
i = 0;
dp = (DWORD*)buf;
*dp = unit;
i += sizeof(DWORD);
dp = (DWORD*)&buf[i];
*dp = nKey;
i += sizeof(DWORD);
memcpy(&buf[i], pFcb, sizeof(fcb_t));
i += sizeof(fcb_t);
dp = (DWORD*)&buf[i];
*dp = nHumanTime;
i += sizeof(DWORD);
return (DWORD)SCSI_CalCmd(buf, i, (BYTE*)pFcb, sizeof(fcb_t));
}
//---------------------------------------------------------------------------
//
// $50 - Get capacity
//
//---------------------------------------------------------------------------
int FS_GetCapacity(capacity_t* cap)
{
BYTE buf[256];
DWORD *dp;
int i;
i = 0;
dp = (DWORD*)buf;
*dp = unit;
i += sizeof(DWORD);
return SCSI_CalCmd(buf, i, (BYTE*)cap, sizeof(capacity_t));
}
//---------------------------------------------------------------------------
//
// $51 - Inspect/control drive status
//
//---------------------------------------------------------------------------
int FS_CtrlDrive(ctrldrive_t* pCtrlDrive)
{
#if 1
// Do tentative processing here due to high load
switch (pCtrlDrive->status) {
case 0: // Inspect status
case 9: // Inspect status 2
pCtrlDrive->status = 0x42;
return pCtrlDrive->status;
case 1: // Eject
case 2: // Eject forbidden 1 (not implemented)
case 3: // Eject allowed 1 (not implemented)
case 4: // Flash LED when media is not inserted (not implemented)
case 5: // Turn off LED when media is not inserted (not implemented)
case 6: // Eject forbidden 2 (not implemented)
case 7: // Eject allowed 2 (not implemented)
return 0;
case 8: // Eject inspection
return 1;
}
return -1;
#else
BYTE buf[256];
DWORD *dp;
int i;
i = 0;
dp = (DWORD*)buf;
*dp = unit;
i += sizeof(DWORD);
memcpy(&buf[i], pCtrlDrive, sizeof(ctrldrive_t));
i += sizeof(ctrldrive_t);
return SCSI_CalCmd(buf, i, (BYTE*)pCtrlDrive, sizeof(ctrldrive_t));
#endif
}
//---------------------------------------------------------------------------
//
// $52 - Get DPB
//
//---------------------------------------------------------------------------
int FS_GetDPB(dpb_t* pDpb)
{
BYTE buf[256];
DWORD *dp;
int i;
i = 0;
dp = (DWORD*)buf;
*dp = unit;
i += sizeof(DWORD);
return SCSI_CalCmd(buf, i, (BYTE*)pDpb, sizeof(dpb_t));
}
//---------------------------------------------------------------------------
//
// $53 - Read sector
//
//---------------------------------------------------------------------------
int FS_DiskRead(BYTE* pBuffer, DWORD nSector, DWORD nSize)
{
BYTE buf[256];
DWORD *dp;
int i;
i = 0;
dp = (DWORD*)buf;
*dp = unit;
i += sizeof(DWORD);
dp = (DWORD*)&buf[i];
*dp = nSector;
i += sizeof(DWORD);
dp = (DWORD*)&buf[i];
*dp = nSize;
i += sizeof(DWORD);
return SCSI_CalCmd(buf, i, (BYTE*)pBuffer, 0x200);
}
//---------------------------------------------------------------------------
//
// $54 - Write sector
//
//---------------------------------------------------------------------------
int FS_DiskWrite()
{
BYTE buf[256];
DWORD *dp;
dp = (DWORD*)buf;
*dp = unit;
return SCSI_SendCmd(buf, 4);
}
//---------------------------------------------------------------------------
//
// $55 - IOCTRL
//
//---------------------------------------------------------------------------
int FS_Ioctrl(DWORD nFunction, ioctrl_t* pIoctrl)
{
BYTE buf[256];
DWORD *dp;
int i;
i = 0;
dp = (DWORD*)buf;
*dp = unit;
i += sizeof(DWORD);
dp = (DWORD*)&buf[i];
*dp = nFunction;
i += sizeof(DWORD);
memcpy(&buf[i], pIoctrl, sizeof(ioctrl_t));
i += sizeof(ioctrl_t);
return SCSI_CalCmd(buf, i, (BYTE*)pIoctrl, sizeof(ioctrl_t));
}
//---------------------------------------------------------------------------
//
// $56 - Flush
//
//---------------------------------------------------------------------------
int FS_Flush()
{
#if 1
// Not supported
return 0;
#else
BYTE buf[256];
DWORD *dp;
dp = (DWORD*)buf;
*dp = unit;
return SCSI_SendCmd(buf, 4);
#endif
}
//---------------------------------------------------------------------------
//
// $57 - Media change check
//
//---------------------------------------------------------------------------
int FS_CheckMedia()
{
#if 1
// Do tentative processing due to high load
return 0;
#else
BYTE buf[256];
DWORD *dp;
dp = (DWORD*)buf;
*dp = unit;
return SCSI_SendCmd(buf, 4);
#endif
}
//---------------------------------------------------------------------------
//
// $58 - Lock
//
//---------------------------------------------------------------------------
int FS_Lock()
{
#if 1
// Not supported
return 0;
#else
BYTE buf[256];
DWORD *dp;
dp = (DWORD*)buf;
*dp = unit;
return SCSI_SendCmd(buf, 4);
#endif
}
//===========================================================================
//
// Command handlers
//
//===========================================================================
#define GetReqByte(a) (request[a])
#define SetReqByte(a,d) (request[a] = (d))
#define GetReqWord(a) (*((WORD*)&request[a]))
#define SetReqWord(a,d) (*((WORD*)&request[a]) = (d))
#define GetReqLong(a) (*((DWORD*)&request[a]))
#define SetReqLong(a,d) (*((DWORD*)&request[a]) = (d))
#define GetReqAddr(a) ((BYTE*)((*((DWORD*)&request[a])) & 0x00ffffff))
//---------------------------------------------------------------------------
//
// Read NAMESTS
//
//---------------------------------------------------------------------------
void GetNameStsPath(BYTE *addr, namests_t* pNamests)
{
DWORD i;
ASSERT(this);
ASSERT(pNamests);
// Wildcard data
pNamests->wildcard = *addr;
// Drive number
pNamests->drive = addr[1];
// Pathname
for (i = 0; i < sizeof(pNamests->path); i++) {
pNamests->path[i] = addr[2 + i];
}
// Filename 1
memset(pNamests->name, 0x20, sizeof(pNamests->name));
// File ending
memset(pNamests->ext, 0x20, sizeof(pNamests->ext));
// Filename 2
memset(pNamests->add, 0, sizeof(pNamests->add));
}
//---------------------------------------------------------------------------
//
// Read NAMESTS
//
//---------------------------------------------------------------------------
void GetNameSts(BYTE *addr, namests_t* pNamests)
{
DWORD i;
ASSERT(this);
ASSERT(pNamests);
ASSERT(addr <= 0xFFFFFF);
// Wildcard data
pNamests->wildcard = *addr;
// Drive number
pNamests->drive = addr[1];
// Pathname
for (i = 0; i < sizeof(pNamests->path); i++) {
pNamests->path[i] = addr[2 + i];
}
// Filename 1
for (i = 0; i < sizeof(pNamests->name); i++) {
pNamests->name[i] = addr[67 + i];
}
// File ending
for (i = 0; i < sizeof(pNamests->ext); i++) {
pNamests->ext[i] = addr[75 + i];
}
// Filename 2
for (i = 0; i < sizeof(pNamests->add); i++) {
pNamests->add[i] = addr[78 + i];
}
}
//---------------------------------------------------------------------------
//
// Read FILES
//
//---------------------------------------------------------------------------
void GetFiles(BYTE *addr, files_t* pFiles)
{
ASSERT(this);
ASSERT(pFiles);
ASSERT(addr <= 0xFFFFFF);
// Search data
pFiles->fatr = *addr;
pFiles->sector = *((DWORD*)&addr[2]);
pFiles->offset = *((WORD*)&addr[8]);;
pFiles->attr = 0;
pFiles->time = 0;
pFiles->date = 0;
pFiles->size = 0;
memset(pFiles->full, 0, sizeof(pFiles->full));
}
//---------------------------------------------------------------------------
//
// Write FILES
//
//---------------------------------------------------------------------------
void SetFiles(BYTE *addr, const files_t* pFiles)
{
DWORD i;
ASSERT(this);
ASSERT(pFiles);
*((DWORD*)&addr[2]) = pFiles->sector;
*((WORD*)&addr[8]) = pFiles->offset;
// File data
addr[21] = pFiles->attr;
*((WORD*)&addr[22]) = pFiles->time;
*((WORD*)&addr[24]) = pFiles->date;
*((DWORD*)&addr[26]) = pFiles->size;
// Full filename
addr += 30;
for (i = 0; i < sizeof(pFiles->full); i++) {
*addr = pFiles->full[i];
addr++;
}
}
//---------------------------------------------------------------------------
//
// Read FCB
//
//---------------------------------------------------------------------------
void GetFcb(BYTE *addr, fcb_t* pFcb)
{
ASSERT(this);
ASSERT(pFcb);
// FCB data
pFcb->fileptr = *((DWORD*)&addr[6]);
pFcb->mode = *((WORD*)&addr[14]);
// Attribute
pFcb->attr = addr[47];
// FCB data
pFcb->time = *((WORD*)&addr[58]);
pFcb->date = *((WORD*)&addr[60]);
pFcb->size = *((DWORD*)&addr[64]);
}
//---------------------------------------------------------------------------
//
// Write FCB
//
//---------------------------------------------------------------------------
void SetFcb(BYTE *addr, const fcb_t* pFcb)
{
ASSERT(this);
ASSERT(pFcb);
// FCB data
*((DWORD*)&addr[6]) = pFcb->fileptr;
*((WORD*)&addr[14]) = pFcb->mode;
// Attribute
addr[47] = pFcb->attr;
// FCB data
*((WORD*)&addr[58]) = pFcb->time;
*((WORD*)&addr[60]) = pFcb->date;
*((DWORD*)&addr[64]) = pFcb->size;
}
//---------------------------------------------------------------------------
//
// Write CAPACITY
//
//---------------------------------------------------------------------------
void SetCapacity(BYTE *addr, const capacity_t* pCapacity)
{
ASSERT(this);
ASSERT(pCapacity);
*((WORD*)&addr[0]) = pCapacity->freearea;
*((WORD*)&addr[2]) = pCapacity->clusters;
*((WORD*)&addr[4]) = pCapacity->sectors;
*((WORD*)&addr[6]) = pCapacity->bytes;
}
//---------------------------------------------------------------------------
//
// Write DPB
//
//---------------------------------------------------------------------------
void SetDpb(BYTE *addr, const dpb_t* pDpb)
{
ASSERT(this);
ASSERT(pDpb);
// DPB data
*((WORD*)&addr[0]) = pDpb->sector_size;
addr[2] = pDpb->cluster_size;
addr[3] = pDpb->shift;
*((WORD*)&addr[4]) = pDpb->fat_sector;
addr[6] = pDpb->fat_max;
addr[7] = pDpb->fat_size;
*((WORD*)&addr[8]) = pDpb->file_max;
*((WORD*)&addr[10]) = pDpb->data_sector;
*((WORD*)&addr[12]) = pDpb->cluster_max;
*((WORD*)&addr[14]) = pDpb->root_sector;
addr[20] = pDpb->media;
}
//---------------------------------------------------------------------------
//
// Read IOCTRL
//
//---------------------------------------------------------------------------
void GetIoctrl(DWORD param, DWORD func, ioctrl_t* pIoctrl)
{
DWORD *lp;
ASSERT(this);
ASSERT(pIoctrl);
switch (func) {
case 2:
// Re-identify media
pIoctrl->param = param;
return;
case -2:
// Configure options
lp = (DWORD*)param;
pIoctrl->param = *lp;
return;
}
}
//---------------------------------------------------------------------------
//
// Write IOCTRL
//
//---------------------------------------------------------------------------
void SetIoctrl(DWORD param, DWORD func, ioctrl_t* pIoctrl)
{
DWORD i;
BYTE *bp;
WORD *wp;
DWORD *lp;
ASSERT(this);
ASSERT(pIoctrl);
switch (func) {
case 0:
// Acquire media ID
wp = (WORD*)param;
*wp = pIoctrl->media;
return;
case 1:
// Dummy for Human68k compatibility
lp = (DWORD*)param;
*lp = pIoctrl->param;
return;
case -1:
// Resident evaluation
bp = (BYTE*)param;
for (i = 0; i < 8; i++) {
*bp = pIoctrl->buffer[i];
bp++;
}
return;
case -3:
// Acquire options
lp = (DWORD*)param;
*lp = pIoctrl->param;
return;
}
}
//---------------------------------------------------------------------------
//
// Read ARGUMENT
//
// When this exceeds the buffer size, interrupt transfer and exit.
//
//---------------------------------------------------------------------------
void GetArgument(BYTE *addr, argument_t* pArgument)
{
BOOL bMode;
BYTE *p;
DWORD i;
BYTE c;
ASSERT(this);
ASSERT(pArgument);
bMode = FALSE;
p = pArgument->buf;
for (i = 0; i < sizeof(pArgument->buf) - 2; i++) {
c = addr[i];
*p++ = c;
if (bMode == 0) {
if (c == '\0')
return;
bMode = TRUE;
} else {
if (c == '\0')
bMode = FALSE;
}
}
*p++ = '\0';
*p = '\0';
}
//---------------------------------------------------------------------------
//
// Write return value
//
//---------------------------------------------------------------------------
void SetResult(DWORD nResult)
{
DWORD code;
ASSERT(this);
// Handle fatal errors
switch (nResult) {
case FS_FATAL_INVALIDUNIT:
code = 0x5001;
goto fatal;
case FS_FATAL_INVALIDCOMMAND:
code = 0x5003;
goto fatal;
case FS_FATAL_WRITEPROTECT:
code = 0x700D;
goto fatal;
case FS_FATAL_MEDIAOFFLINE:
code = 0x7002;
fatal:
SetReqByte(3, (BYTE)code);
SetReqByte(4, code >> 8);
// @note When returning retryability, never overwrite with (a5 + 18).
// If you do that, the system will start behaving erratically if you hit Retry at the system error screen.
if (code & 0x2000)
break;
nResult = FS_INVALIDFUNC;
default:
SetReqLong(18, nResult);
break;
}
}
//---------------------------------------------------------------------------
//
// $40 - Device startup
//
// in (offset size)
// 0 1.b constant (22)
// 2 1.b command ($40/$c0)
// 18 1.l parameter address
// 22 1.b drive number
// out (offset size)
// 3 1.b error code (lower)
// 4 1.b '' (upper)
// 13 1.b number of units
// 14 1.l device driver exit address + 1
//
// This is called command 0 when the driver is loaded similarly to a local drive,
// but there is no need to prepare BPB or its pointer array.
// Unlike other commands, only this command does not include a valid a5 + 1,
// since it doesn't expect 0 initialization etc., so be careful.
//
//---------------------------------------------------------------------------
DWORD InitDevice(void)
{
argument_t arg;
DWORD units;
ASSERT(this);
ASSERT(fs);
// Get option contents
GetArgument(GetReqAddr(18), &arg);
// Contstruct the filesystem to the extent Human68k can support number of drivers etc.
units = FS_InitDevice(&arg);
// Return number of drives
SetReqByte(13, units);
return 0;
}
//---------------------------------------------------------------------------
//
// $41 - Directory check
//
// in (offset size)
// 14 1.L NAMESTS struct address
//
//---------------------------------------------------------------------------
DWORD CheckDir(void)
{
namests_t ns;
int nResult;
ASSERT(this);
ASSERT(fs);
// Get filename to search
GetNameStsPath(GetReqAddr(14), &ns);
// Call filesystem
nResult = FS_CheckDir(&ns);
return nResult;
}
//---------------------------------------------------------------------------
//
// $42 - Create directory
//
// in (offset size)
// 14 1.L NAMESTS struct address
//
//---------------------------------------------------------------------------
DWORD MakeDir(void)
{
namests_t ns;
int nResult;
ASSERT(this);
ASSERT(fs);
// Get filename to search
GetNameSts(GetReqAddr(14), &ns);
// Call filesystem
nResult = FS_MakeDir(&ns);
return nResult;
}
//---------------------------------------------------------------------------
//
// $43 - Delete directory
//
// in (offset size)
// 14 1.L NAMESTS struct address
//
//---------------------------------------------------------------------------
DWORD RemoveDir(void)
{
namests_t ns;
int nResult;
ASSERT(this);
ASSERT(fs);
// Get filename to search
GetNameSts(GetReqAddr(14), &ns);
// Call filesystem
nResult = FS_RemoveDir(&ns);
return nResult;
}
//---------------------------------------------------------------------------
//
// $44 - Change filename
//
// in (offset size)
// 14 1.L NAMESTS struct address old filename
// 18 1.L NAMESTS struct address new filename
//
//---------------------------------------------------------------------------
DWORD Rename(void)
{
namests_t ns;
namests_t ns_new;
int nResult;
ASSERT(this);
ASSERT(fs);
// Get filename to search
GetNameSts(GetReqAddr(14), &ns);
GetNameSts(GetReqAddr(18), &ns_new);
// Call filesystem
nResult = FS_Rename(&ns, &ns_new);
return nResult;
}
//---------------------------------------------------------------------------
//
// $45 - Delete file
//
// in (offset size)
// 14 1.L NAMESTS struct address
//
//---------------------------------------------------------------------------
DWORD Delete(void)
{
namests_t ns;
int nResult;
ASSERT(this);
ASSERT(fs);
// Get filename to search
GetNameSts(GetReqAddr(14), &ns);
// Call filesystem
nResult = FS_Delete(&ns);
return nResult;
}
//---------------------------------------------------------------------------
//
// $46 - Get/set file attribute
//
// in (offset size)
// 12 1.B Note that this becomes 0x01 when read from memory
// 13 1.B attribute; read from memory when $FF
// 14 1.L NAMESTS struct address
//
//---------------------------------------------------------------------------
DWORD Attribute(void)
{
namests_t ns;
DWORD attr;
int nResult;
ASSERT(this);
ASSERT(fs);
// Get filename to search
GetNameSts(GetReqAddr(14), &ns);
// Target attribute
attr = GetReqByte(13);
// Call filesystem
nResult = FS_Attribute(&ns, attr);
return nResult;
}
//---------------------------------------------------------------------------
//
// $47 - File search
//
// in (offset size)
// 0 1.b constant (26)
// 1 1.b unit number
// 2 1.b command ($47/$c7)
// 13 1.b search attribute (Unused in WindrvXM. Written directly to search buffer.)
// 14 1.l Filename buffer (namests format)
// 18 1.l Search buffer (files format) Search data in progress and search results are written to this buffer.
// out (offset size)
// 3 1.b error code (lower)
// 4 1.b '' (upper)
// 18 1.l result status
//
// Search files from specified directory. Called from DOS _FILES.
// When a search fails, or succeeds but not using wildcards,
// we write -1 to the search buffer offset to make the next search fail.
// When a file is found, we set its data as well as the following data
// for the next search: sector number, offset, and in the case of the
// root directory, also the remaining sectors. The search drive, attribute,
// and path name are set in the DOS call processing, so writing is not needed.
//
// <NAMESTS struct>
// (offset size)
// 0 1.b NAMWLD 0: no wildcard -1:no specified file
// (number of chars of wildcard)
// 1 1.b NAMDRV drive number (A=0,B=1,...,Z=25)
// 2 65.b NAMPTH path ('\' + optional subdirectory + '\')
// 67 8.b NAMNM1 filename (first 8 chars)
// 75 3.b NAMEXT file ending
// 78 10.b NAMNM2 filename (remaining 10 chars)
//
// Note that 0x09 (TAB) is used for path separator, rather than 0x2F (/) or 0x5C (\)
//
//---------------------------------------------------------------------------
DWORD Files(void)
{
BYTE *files;
files_t info;
namests_t ns;
int nResult;
ASSERT(this);
ASSERT(fs);
// Memory for storing search in progress
files = GetReqAddr(18);
GetFiles(files, &info);
// Get filename to search
GetNameSts(GetReqAddr(14), &ns);
// Call filesystem
nResult = FS_Files((DWORD)files, &ns, &info);
// Apply search results
if (nResult >= 0) {
SetFiles(files, &info);
}
return nResult;
}
//---------------------------------------------------------------------------
//
// $48 - Search next file
//
// in (offset size)
// 18 1.L FILES struct address
//
//---------------------------------------------------------------------------
DWORD NFiles(void)
{
BYTE *files;
files_t info;
int nResult;
ASSERT(this);
ASSERT(fs);
// Read work memory
files = GetReqAddr(18);
GetFiles(files, &info);
// Call filesystem
nResult = FS_NFiles((DWORD)files, &info);
// Apply search results
if (nResult >= 0) {
SetFiles(files, &info);
}
return nResult;
}
//---------------------------------------------------------------------------
//
// $49 - Create file (Create)
//
// in (offset size)
// 1 1.B unit number
// 13 1.B attribute
// 14 1.L NAMESTS struct address
// 18 1.L mode (0:_NEWFILE 1:_CREATE)
// 22 1.L FCB struct address
//
//---------------------------------------------------------------------------
DWORD Create(void)
{
namests_t ns;
BYTE *pFcb;
fcb_t fcb;
DWORD attr;
BOOL force;
int nResult;
ASSERT(this);
ASSERT(fs);
// Get target filename
GetNameSts(GetReqAddr(14), &ns);
// Get FCB
pFcb = GetReqAddr(22);
GetFcb(pFcb, &fcb);
// Attribute
attr = GetReqByte(13);
// Forced overwrite mode
force = (BOOL)GetReqLong(18);
// Call filesystem
nResult = FS_Create((DWORD)pFcb, &ns, &fcb, attr, force);
// Apply results
if (nResult >= 0) {
SetFcb(pFcb, &fcb);
}
return nResult;
}
//---------------------------------------------------------------------------
//
// $4A - File open
//
// in (offset size)
// 1 1.B unit number
// 14 1.L NAMESTS struct address
// 22 1.L FCB struct address
// Most parameters are already set in FCB.
// Overwrite time and date at the moment of opening.
// Overwrite if size is 0.
//
//---------------------------------------------------------------------------
DWORD Open(void)
{
namests_t ns;
BYTE *pFcb;
fcb_t fcb;
int nResult;
ASSERT(this);
ASSERT(fs);
// Get target filename
GetNameSts(GetReqAddr(14), &ns);
// Get FCB
pFcb = GetReqAddr(22);
GetFcb(pFcb, &fcb);
// Call filesystem
nResult = FS_Open((DWORD)pFcb, &ns, &fcb);
// Apply results
if (nResult >= 0) {
SetFcb(pFcb, &fcb);
}
return nResult;
}
//---------------------------------------------------------------------------
//
// $4B - File close
//
// in (offset size)
// 22 1.L FCB struct address
//
//---------------------------------------------------------------------------
DWORD Close(void)
{
BYTE *pFcb;
fcb_t fcb;
int nResult;
ASSERT(this);
ASSERT(fs);
// Get FCB
pFcb = GetReqAddr(22);
GetFcb(pFcb, &fcb);
// Call filesystem
nResult = FS_Close((DWORD)pFcb, &fcb);
// Apply results
if (nResult >= 0) {
SetFcb(pFcb, &fcb);
}
return nResult;
}
//---------------------------------------------------------------------------
//
// $4C - Read file
//
// in (offset size)
// 14 1.L Reading buffer; Read the file contents here.
// 18 1.L Size; It may be set to values exceeding 16MB
// 22 1.L FCB struct address
//
// No guarantee for behavior when passing address where bus error occurs.
//
// In the 20th century, a small number of apps used a trick where reading a
// negative value meant "read all the files!" Wh, what? This file is over 16MB!
//
// Back then, anything over 4~12MB was treated as "inifity" and often truncated
// out of helpfulness, which is not needed in this day and age.
// On the other hand, it might be a good idea to truncate at 12MB or 16MB.
//
//---------------------------------------------------------------------------
DWORD Read(void)
{
BYTE *pFcb;
fcb_t fcb;
BYTE *pAddress;
DWORD nSize;
int nResult;
ASSERT(this);
ASSERT(fs);
// Get FCB
pFcb = GetReqAddr(22);
GetFcb(pFcb, &fcb);
// Read buffer
pAddress = GetReqAddr(14);
// Read size
nSize = GetReqLong(18);
// Clipping
if (nSize >= WINDRV_CLIPSIZE_MAX) {
nSize = WINDRV_CLIPSIZE_MAX;
}
// Call filesystem
nResult = FS_Read((DWORD)pFcb, &fcb, pAddress, nSize);
// Apply results
if (nResult >= 0) {
SetFcb(pFcb, &fcb);
}
return nResult;
}
//---------------------------------------------------------------------------
//
// $4D - Write file
//
// in (offset size)
// 14 1.L Write buffer; Write file contents here
// 18 1.L Size; If a negative number, treated the same as specifying file size
// 22 1.L FCB struct address
//
// No guarantee for behavior when passing address where bus error occurs.
//
//---------------------------------------------------------------------------
DWORD Write(void)
{
BYTE *pFcb;
fcb_t fcb;
BYTE *pAddress;
DWORD nSize;
int nResult;
ASSERT(this);
ASSERT(fs);
// Get FCB
pFcb = GetReqAddr(22);
GetFcb(pFcb, &fcb);
// Write buffer
pAddress = GetReqAddr(14);
// Write size
nSize = GetReqLong(18);
// Clipping
if (nSize >= WINDRV_CLIPSIZE_MAX) {
nSize = WINDRV_CLIPSIZE_MAX;
}
// Call filesystem
nResult = FS_Write((DWORD)pFcb, &fcb, pAddress, nSize);
// Apply results
if (nResult >= 0) {
SetFcb(pFcb, &fcb);
}
return nResult;
}
//---------------------------------------------------------------------------
//
// $4E - File seek
//
// in (offset size)
// 12 1.B This becomes 0x2B sometimes, and 0 other times
// 13 1.B mode
// 18 1.L offset
// 22 1.L FCB struct address
//
//---------------------------------------------------------------------------
DWORD Seek(void)
{
BYTE *pFcb;
fcb_t fcb;
DWORD nMode;
DWORD nOffset;
int nResult;
ASSERT(this);
ASSERT(fs);
// Get FCB
pFcb = GetReqAddr(22);
GetFcb(pFcb, &fcb);
// Seek mode
nMode = GetReqByte(13);
// Seek offset
nOffset = GetReqLong(18);
// Call filesystem
nResult = FS_Seek((DWORD)pFcb, &fcb, nMode, nOffset);
// Apply results
if (nResult >= 0) {
SetFcb(pFcb, &fcb);
}
return nResult;
}
//---------------------------------------------------------------------------
//
// $4F - Get/set file timestamp
//
// in (offset size)
// 18 1.W DATE
// 20 1.W TIME
// 22 1.L FCB struct address
//
// Possible to change settings when FCB is opened in read mode too.
// Note: Cannot make the judgement of read-only with only FCB
//
//---------------------------------------------------------------------------
DWORD TimeStamp(void)
{
BYTE *pFcb;
fcb_t fcb;
DWORD nTime;
DWORD nResult;
ASSERT(this);
ASSERT(fs);
// Get FCB
pFcb = GetReqAddr(22);
GetFcb(pFcb, &fcb);
// Get timestamp
nTime = GetReqLong(18);
// Call filesystem
nResult = FS_TimeStamp((DWORD)pFcb, &fcb, nTime);
// Apply results
if (nResult < 0xFFFF0000) {
SetFcb(pFcb, &fcb);
}
return nResult;
}
//---------------------------------------------------------------------------
//
// $50 - Get capacity
//
// in (offset size)
// 0 1.b constant (26)
// 1 1.b unit number
// 2 1.b command ($50/$d0)
// 14 1.l buffer address
// out (offset size)
// 3 1.b error code (lower)
// 4 1.b '' (upper)
// 18 1.l result status
//
// Get the total and available media capacity, as well as cluster / sector size.
// The contents to write to buffer follows. Returns number of bytes that can be
// used for result status.
//
// (offset size)
// 0 1.w available number of clusters
// 2 1.w total number of clusters
// 4 1.w number of sectors per 1 cluster
// 6 1.w number of bytes per 1 sector
//
//---------------------------------------------------------------------------
DWORD GetCapacity(void)
{
BYTE *pCapacity;
capacity_t cap;
int nResult;
ASSERT(this);
ASSERT(fs);
// Get buffer
pCapacity = GetReqAddr(14);
#if 0
// Call filesystem
nResult = FS_GetCapacity(&cap);
#else
// Try skipping since the contents are always returned
cap.freearea = 0xFFFF;
cap.clusters = 0xFFFF;
cap.sectors = 64;
cap.bytes = 512;
nResult = 0x7FFF8000;
#endif
// Apply results
if (nResult >= 0) {
SetCapacity(pCapacity, &cap);
}
return nResult;
}
//---------------------------------------------------------------------------
//
// $51 - Inspect/control drive status
//
// in (offset size)
// 1 1.B unit number
// 13 1.B status 0: status inspection 1: eject
//
//---------------------------------------------------------------------------
DWORD CtrlDrive(void)
{
ctrldrive_t ctrl;
int nResult;
ASSERT(this);
ASSERT(fs);
// Get drive status
ctrl.status = GetReqByte(13);
// Call filesystem
nResult = FS_CtrlDrive(&ctrl);
// Apply results
if (nResult >= 0) {
SetReqByte(13, ctrl.status);
}
return nResult;
}
//---------------------------------------------------------------------------
//
// $52 - Get DPB
//
// in (offset size)
// 0 1.b constant (26)
// 1 1.b unit number
// 2 1.b command ($52/$d2)
// 14 1.l buffer address (points at starting address + 2)
// out (offset size)
// 3 1.b error code (lower)
// 4 1.b '' (upper)
// 18 1.l result status
//
// Specified media data is returned as DPB v1. Data needed to be set
// for this command are as follows (parantheses indicate what's set by DOS calls.)
// Note that the buffer adress is what's pointed at by offset 2.
//
// (offset size)
// 0 1.b (drive number)
// 1 1.b (unit number)
// 2 1.w number of bytes per 1 sector
// 4 1.b number of sectors - 1 per 1 cluster
// 5 1.b Number of cluster -> sector
// bit 7 = 1 in MS-DOS format FAT (16bit Intel array)
// 6 1.w FAT first sector number
// 8 1.b Number of FAT allocations
// 9 1.b Number of FAT controlled sectors (excluding duplicates)
// 10 1.w Number of files in the root directory
// 12 1.w First sector number of data memory
// 14 1.w Total number of clusters + 1
// 16 1.w First sector number of root directory
// 18 1.l (Driver head address)
// 22 1.b (Physical drive name in lower-case)
// 23 1.b (DPB usage flag: normally 0)
// 24 1.l (Next DPB address)
// 28 1.w (Cluster number of current directory: normally 0)
// 30 64.b (Current directory name)
//
//---------------------------------------------------------------------------
DWORD GetDPB(void)
{
BYTE *pDpb;
dpb_t dpb;
int nResult;
ASSERT(this);
ASSERT(fs);
// Get DPB
pDpb = GetReqAddr(14);
// Call filesystem
nResult = FS_GetDPB(&dpb);
// Apply results
if (nResult >= 0) {
SetDpb(pDpb, &dpb);
}
return nResult;
}
//---------------------------------------------------------------------------
//
// $53 - Read sector
//
// in (offset size)
// 1 1.B unit number
// 14 1.L buffer address
// 18 1.L number of sectors
// 22 1.L sector number
//
//---------------------------------------------------------------------------
DWORD DiskRead(void)
{
BYTE *pAddress;
DWORD nSize;
DWORD nSector;
BYTE buffer[0x200];
int nResult;
int i;
ASSERT(this);
ASSERT(fs);
pAddress = GetReqAddr(14); // Address (upper bit is extension flag)
nSize = GetReqLong(18); // Number of sectors
nSector = GetReqLong(22); // Sector number
// Call filesystem
nResult = FS_DiskRead(buffer, nSector, nSize);
// Apply results
if (nResult >= 0) {
for (i = 0; i < sizeof(buffer); i++) {
*pAddress = buffer[i];
pAddress++;
}
}
return nResult;
}
//---------------------------------------------------------------------------
//
// $54 - Write sector
//
// in (offset size)
// 1 1.B unit number
// 14 1.L buffer address
// 18 1.L number of sectors
// 22 1.L sector number
//
//---------------------------------------------------------------------------
DWORD DiskWrite(void)
{
BYTE *pAddress;
DWORD nSize;
DWORD nSector;
int nResult;
ASSERT(this);
ASSERT(fs);
pAddress = GetReqAddr(14); // Address (upper bit is extension flag)
nSize = GetReqLong(18); // Number of sectors
nSector = GetReqLong(22); // Sector number
// Call filesystem
nResult = FS_DiskWrite();
return nResult;
}
//---------------------------------------------------------------------------
//
// $55 - IOCTRL
//
// in (offset size)
// 1 1.B unit number
// 14 1.L parameter
// 18 1.W feature number
//
//---------------------------------------------------------------------------
DWORD Ioctrl(void)
{
DWORD param;
DWORD func;
ioctrl_t ioctrl;
int nResult;
ASSERT(this);
ASSERT(fs);
// Get IOCTRL
param = GetReqLong(14); // Parameter
func = GetReqWord(18); // Feature number
GetIoctrl(param, func, &ioctrl);
// Call filesystem
nResult = FS_Ioctrl(func, &ioctrl);
// Apply results
if (nResult >= 0)
SetIoctrl(param, func, &ioctrl);
return nResult;
}
//---------------------------------------------------------------------------
//
// $56 - Flush
//
// in (offset size)
// 1 1.b unit number
//
//---------------------------------------------------------------------------
DWORD Flush(void)
{
int nResult;
ASSERT(this);
ASSERT(fs);
// Call filesystem
nResult = FS_Flush();
return nResult;
}
//---------------------------------------------------------------------------
//
// $57 - Media change check
//
// in (offset size)
// 0 1.b constant (26)
// 1 1.b unit number
// 2 1.b Command ($57/$d7)
// out (offset size)
// 3 1.b error code (lower)
// 4 1.b '' (upper)
// 18 1.l result status
//
// Checks if the media has been changed or not. Format if it has changed.
// The verification is done within this command.
//
//---------------------------------------------------------------------------
DWORD CheckMedia(void)
{
int nResult;
ASSERT(this);
ASSERT(fs);
// Call filesystem
nResult = FS_CheckMedia();
return nResult;
}
//---------------------------------------------------------------------------
//
// $58 - Lock
//
// in (offset size)
// 1 1.b unit number
//
//---------------------------------------------------------------------------
DWORD Lock(void)
{
int nResult;
ASSERT(this);
ASSERT(fs);
// Call filesystem
nResult = FS_Lock();
return nResult;
}
//---------------------------------------------------------------------------
//
// Execute command
//
//---------------------------------------------------------------------------
DWORD ExecuteCommand()
{
ASSERT(this);
// Clear error data
SetReqByte(3, 0);
SetReqByte(4, 0);
// Command number
command = (DWORD)GetReqByte(2); // Bit 7 is verify flag
// Unit number
unit = GetReqByte(1);
// Command branching
switch (command & 0x7F) {
case 0x40: return InitDevice(); // $40 - Device startup
case 0x41: return CheckDir(); // $41 - Directory check
case 0x42: return MakeDir(); // $42 - Create directory
case 0x43: return RemoveDir(); // $43 - Delete directory
case 0x44: return Rename(); // $44 - Change file name
case 0x45: return Delete(); // $45 - Delete file
case 0x46: return Attribute(); // $46 - Get / set file attribute
case 0x47: return Files(); // $47 - Find file
case 0x48: return NFiles(); // $48 - Find next file
case 0x49: return Create(); // $49 - Create file
case 0x4A: return Open(); // $4A - Open file
case 0x4B: return Close(); // $4B - Close file
case 0x4C: return Read(); // $4C - Read file
case 0x4D: return Write(); // $4D - Write file
case 0x4E: return Seek(); // $4E - Seek file
case 0x4F: return TimeStamp(); // $4F - Get / set file timestamp
case 0x50: return GetCapacity();// $50 - Get capacity
case 0x51: return CtrlDrive(); // $51 - Inspect / control drive status
case 0x52: return GetDPB(); // $52 - Get DPB
case 0x53: return DiskRead(); // $53 - Read sectors
case 0x54: return DiskWrite(); // $54 - Write sectors
case 0x55: return Ioctrl(); // $55 - IOCTRL
case 0x56: return Flush(); // $56 - Flush
case 0x57: return CheckMedia(); // $57 - Media change check
case 0x58: return Lock(); // $58 - Lock
}
return FS_FATAL_INVALIDCOMMAND;
}
//---------------------------------------------------------------------------
//
// Initialization
//
//---------------------------------------------------------------------------
BOOL Init()
{
ASSERT(this);
return SCSI_Init();
}
//---------------------------------------------------------------------------
//
// Execution
//
//---------------------------------------------------------------------------
void Process(DWORD nA5)
{
ASSERT(this);
ASSERT(nA5 <= 0xFFFFFF);
ASSERT(m_bAlloc);
ASSERT(m_bFree);
// Request header address
request = (BYTE*)nA5;
// Command execution
SetResult(ExecuteCommand());
}