mirror of
https://github.com/akuker/RASCSI.git
synced 2024-06-13 23:29:30 +00:00
* 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
2431 lines
52 KiB
C
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());
|
|
}
|