mirror of
https://github.com/LIV2/lide.device.git
synced 2025-12-06 00:32:45 +00:00
1184 lines
31 KiB
C
1184 lines
31 KiB
C
// Generic autoboot/automount RDB parser and mounter.
|
|
// - KS 1.3 support, including autoboot mode.
|
|
// - 68000 compatible.
|
|
// - Boot ROM and executable modes.
|
|
// - Autoboot capable (Boot ROM mode only).
|
|
// - Full automount support
|
|
// - Full RDB filesystem support.
|
|
//
|
|
// Copyright 2021-2022 Toni Wilen
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are met:
|
|
//
|
|
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
// list of conditions and the following disclaimer.
|
|
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
// this list of conditions and the following disclaimer in the documentation
|
|
// and/or other materials provided with the distribution.
|
|
//
|
|
#ifdef DEBUG_MOUNTER
|
|
#define USE_SERIAL_OUTPUT
|
|
#endif
|
|
#include <string.h>
|
|
|
|
#include <exec/types.h>
|
|
#include <exec/memory.h>
|
|
#include <exec/alerts.h>
|
|
#include <exec/ports.h>
|
|
#include <exec/execbase.h>
|
|
#include <exec/io.h>
|
|
#include <devices/trackdisk.h>
|
|
#include <devices/hardblocks.h>
|
|
#include <devices/scsidisk.h>
|
|
#include <resources/filesysres.h>
|
|
#include <libraries/expansion.h>
|
|
#include <libraries/expansionbase.h>
|
|
#include <libraries/configvars.h>
|
|
#include <clib/alib_protos.h>
|
|
#include <dos/dos.h>
|
|
#include <dos/dosextens.h>
|
|
#include <dos/doshunks.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdbool.h>
|
|
|
|
#include <proto/exec.h>
|
|
#include <proto/expansion.h>
|
|
#include <proto/dos.h>
|
|
|
|
#include "ndkcompat.h"
|
|
#include "mounter.h"
|
|
#include "scsi.h"
|
|
|
|
#if TRACE
|
|
#define dbg Trace
|
|
#else
|
|
#define dbg
|
|
#endif
|
|
|
|
#define MAX_BLOCKSIZE 2048
|
|
#define LSEG_DATASIZE (512 / 4 - 5)
|
|
|
|
#if NO_CONFIGDEV
|
|
extern UBYTE entrypoint, entrypoint_end;
|
|
extern UBYTE bootblock, bootblock_end;
|
|
#endif
|
|
|
|
struct ExecBase *SysBase;
|
|
struct FileSysResource *FileSysResBase = NULL;
|
|
|
|
struct MountData
|
|
{
|
|
struct ExecBase *SysBase;
|
|
struct ExpansionBase *ExpansionBase;
|
|
struct DosLibrary *DOSBase;
|
|
struct IOExtTD *request;
|
|
struct ConfigDev *configDev;
|
|
const UBYTE *creator;
|
|
const UBYTE *devicename;
|
|
|
|
ULONG lsegblock;
|
|
ULONG lseglongs;
|
|
ULONG lsegoffset;
|
|
struct LoadSegBlock *lsegbuf;
|
|
UWORD lsegwordbuf;
|
|
UWORD lseghasword;
|
|
|
|
ULONG unitnum;
|
|
LONG ret;
|
|
UBYTE buf[MAX_BLOCKSIZE * 3];
|
|
UBYTE zero[2];
|
|
BOOL wasLastDev;
|
|
int blocksize;
|
|
};
|
|
|
|
// Get Block size of unit by sending a SCSI READ CAPACITY 10 command
|
|
int GetBlockSize(struct IOStdReq *req) {
|
|
struct SCSICmd *cmd = MakeSCSICmd(SZ_CDB_10);
|
|
|
|
if (cmd == NULL) return 0;
|
|
|
|
struct SCSI_READ_CAPACITY_10 *cdb = (struct SCSI_READ_CAPACITY_10 *)cmd->scsi_Command;
|
|
BYTE err;
|
|
int ret = -1;
|
|
|
|
struct SCSI_CAPACITY_10 *result = AllocMem(sizeof(struct SCSI_CAPACITY_10),MEMF_CLEAR|MEMF_ANY);
|
|
|
|
if (!result) {
|
|
DeleteSCSICmd(cmd);
|
|
return -1;
|
|
}
|
|
|
|
cdb->operation = SCSI_CMD_READ_CAPACITY_10;
|
|
cmd->scsi_Length = sizeof(struct SCSI_CAPACITY_10);
|
|
cmd->scsi_Data = (UWORD *)result;
|
|
cmd->scsi_Flags = SCSIF_READ;
|
|
cdb->lba = 0;
|
|
|
|
req->io_Command = HD_SCSICMD;
|
|
req->io_Data = cmd;
|
|
req->io_Length = sizeof(struct SCSICmd);
|
|
|
|
for (int retry = 0; retry < 3; retry++) {
|
|
if ((err = DoIO((struct IORequest *)req)) == 0) break;
|
|
}
|
|
|
|
if (err == 0 && req->io_Length > 0) {
|
|
ret = result->block_size;
|
|
} else {
|
|
ret = -1;
|
|
}
|
|
|
|
if (cmd) DeleteSCSICmd(cmd);
|
|
if (result) FreeMem(result,sizeof(struct SCSI_CAPACITY_10));
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if CDBOOT
|
|
// CheckPVD
|
|
// Check for "CDTV" or "AMIGA BOOT" as the System ID in the PVD
|
|
bool CheckPVD(struct IOStdReq *ior) {
|
|
const char sys_id_1[] = "CDTV";
|
|
const char sys_id_2[] = "AMIGA BOOT";
|
|
const char iso_id[] = "CD001";
|
|
|
|
BYTE err = 0;
|
|
BOOL ret = false;
|
|
char *buf = NULL;
|
|
|
|
if (!(buf = AllocMem(2048,MEMF_ANY|MEMF_CLEAR))) goto done;
|
|
|
|
ior->io_Command = TD_CHANGESTATE; // Check if there's a disc in the drive
|
|
|
|
if (err = DoIO((struct IORequest *)ior) || ior->io_Actual != 0) goto done;
|
|
|
|
char *id_string = buf + 1;
|
|
char *system_id = buf + 8;
|
|
|
|
ior->io_Command = CMD_READ;
|
|
ior->io_Data = buf;
|
|
ior->io_Length = 2048;
|
|
|
|
for (int i=0; i < 32; i++) {
|
|
|
|
ior->io_Offset = (i + 16) << 11;
|
|
|
|
for (int retry = 0; retry < 3; retry++) {
|
|
if ((err = DoIO((struct IORequest*)ior)) == 0) break;
|
|
}
|
|
|
|
if (ior->io_Actual < 2048) break;
|
|
|
|
// Check ISO ID String & for PVD Version & Type code
|
|
if ((strncmp(iso_id,id_string,5) == 0) && buf[0] == 1 && buf[6] == 1) {
|
|
if (strncmp(sys_id_1,system_id,strlen(sys_id_1)) == 0 || strncmp(sys_id_2,system_id,strlen(sys_id_2) == 0)) {
|
|
ret = true; // CDTV or AMIGA BOOT
|
|
} else {
|
|
ret = false;
|
|
}
|
|
break;
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
}
|
|
done:
|
|
if (buf) FreeMem(buf,2048);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
// KS 1.3 compatibility functions
|
|
APTR W_CreateIORequest(struct MsgPort *ioReplyPort, ULONG size, struct ExecBase *SysBase)
|
|
{
|
|
struct IORequest *ret = NULL;
|
|
if(ioReplyPort == NULL)
|
|
return NULL;
|
|
ret = (struct IORequest*)AllocMem(size, MEMF_PUBLIC | MEMF_CLEAR);
|
|
if(ret != NULL)
|
|
{
|
|
ret->io_Message.mn_ReplyPort = ioReplyPort;
|
|
ret->io_Message.mn_Length = size;
|
|
}
|
|
return ret;
|
|
}
|
|
void W_DeleteIORequest(APTR iorequest, struct ExecBase *SysBase)
|
|
{
|
|
if(iorequest != NULL) {
|
|
FreeMem(iorequest, ((struct Message*)iorequest)->mn_Length);
|
|
}
|
|
}
|
|
struct MsgPort *W_CreateMsgPort(struct ExecBase *SysBase)
|
|
{
|
|
struct MsgPort *ret;
|
|
ret = (struct MsgPort*)AllocMem(sizeof(struct MsgPort), MEMF_PUBLIC | MEMF_CLEAR);
|
|
if(ret != NULL)
|
|
{
|
|
BYTE sb = AllocSignal(-1);
|
|
if (sb != -1)
|
|
{
|
|
ret->mp_Flags = PA_SIGNAL;
|
|
ret->mp_Node.ln_Type = NT_MSGPORT;
|
|
NewList(&ret->mp_MsgList);
|
|
ret->mp_SigBit = sb;
|
|
ret->mp_SigTask = FindTask(NULL);
|
|
return ret;
|
|
}
|
|
FreeMem(ret, sizeof(struct MsgPort));
|
|
}
|
|
return NULL;
|
|
}
|
|
void W_DeleteMsgPort(struct MsgPort *port, struct ExecBase *SysBase)
|
|
{
|
|
if(port != NULL)
|
|
{
|
|
FreeSignal(port->mp_SigBit);
|
|
FreeMem(port, sizeof(struct MsgPort));
|
|
}
|
|
}
|
|
|
|
// Flush cache (Filesystem relocation)
|
|
static void cacheclear(struct MountData *md)
|
|
{
|
|
struct ExecBase *SysBase = md->SysBase;
|
|
if (SysBase->LibNode.lib_Version >= 37) {
|
|
//CacheClearU();
|
|
}
|
|
}
|
|
|
|
// Simply memory copy.
|
|
// Only used for few short copies, it does not need to be optimal.
|
|
// Required because compiler built-in memcpy() can have
|
|
// extra dependencies which will make boot rom build
|
|
// impossible.
|
|
static void copymem(void *dstp, void *srcp, UWORD size)
|
|
{
|
|
UBYTE *dst = (UBYTE*)dstp;
|
|
UBYTE *src = (UBYTE*)srcp;
|
|
while (size != 0) {
|
|
*dst++ = *src++;
|
|
size--;
|
|
}
|
|
}
|
|
|
|
// Check block checksum
|
|
static UWORD checksum(UBYTE *buf, struct MountData *md)
|
|
{
|
|
ULONG chk = 0;
|
|
ULONG num_longs;
|
|
|
|
num_longs = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | (buf[7]);
|
|
if (num_longs > 65535)
|
|
return FALSE;
|
|
|
|
for (UWORD i = 0; i < (int)(num_longs * sizeof(LONG)); i += 4) {
|
|
ULONG v = (buf[i + 0] << 24) | (buf[i + 1] << 16) | (buf[i + 2] << 8) | (buf[i + 3 ] << 0);
|
|
chk += v;
|
|
}
|
|
if (chk) {
|
|
dbg("Checksum error %08"PRIx32"\n", chk);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#define MAX_RETRIES 3
|
|
|
|
// Read single block with retries
|
|
static BOOL readblock(UBYTE *buf, ULONG block, ULONG id, struct MountData *md)
|
|
{
|
|
struct ExecBase *SysBase = md->SysBase;
|
|
struct IOExtTD *request = md->request;
|
|
UWORD i;
|
|
|
|
request->iotd_Req.io_Command = CMD_READ;
|
|
request->iotd_Req.io_Offset = (block * md->blocksize);
|
|
request->iotd_Req.io_Data = buf;
|
|
request->iotd_Req.io_Length = md->blocksize;
|
|
for (i = 0; i < MAX_RETRIES; i++) {
|
|
LONG err = DoIO((struct IORequest*)request);
|
|
if (!err) {
|
|
break;
|
|
}
|
|
dbg("Read block %"PRIu32" error %"PRId32"\n", block, err);
|
|
}
|
|
if (i == MAX_RETRIES) {
|
|
return FALSE;
|
|
}
|
|
ULONG v = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] << 0);
|
|
dbg("Read block %"PRIu32" %08"PRIx32"\n", block, v);
|
|
if (id != 0xffffffff) {
|
|
if (v != id) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
if (!checksum(buf, md)) {
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
// Read multiple longs from LSEG blocks
|
|
static BOOL lseg_read_longs(struct MountData *md, ULONG longs, ULONG *data)
|
|
{
|
|
dbg("lseg_read_longs, longs %"PRId32" ptr %p, remaining %"PRId32"\n", longs, data, md->lseglongs);
|
|
ULONG cnt = 0;
|
|
md->lseghasword = FALSE;
|
|
while (longs > cnt) {
|
|
if (md->lseglongs > 0) {
|
|
data[cnt] = md->lsegbuf->lsb_LoadData[md->lsegoffset];
|
|
md->lsegoffset++;
|
|
md->lseglongs--;
|
|
cnt++;
|
|
if (longs == cnt) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
if (!md->lseglongs) {
|
|
if (md->lsegblock == 0xffffffff) {
|
|
dbg("lseg_read_long premature end!\n");
|
|
return FALSE;
|
|
}
|
|
if (!readblock((UBYTE*)md->lsegbuf, md->lsegblock, IDNAME_LOADSEG, md)) {
|
|
return FALSE;
|
|
}
|
|
md->lseglongs = LSEG_DATASIZE;
|
|
md->lsegoffset = 0;
|
|
dbg("lseg_read_long lseg block %"PRId32" loaded, next %"PRId32"\n", md->lsegblock, md->lsegbuf->lsb_Next);
|
|
md->lsegblock = md->lsegbuf->lsb_Next;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
// Read single long from LSEG blocks
|
|
static BOOL lseg_read_long(struct MountData *md, ULONG *data)
|
|
{
|
|
BOOL v;
|
|
if (md->lseghasword) {
|
|
ULONG temp;
|
|
v = lseg_read_longs(md, 1, &temp);
|
|
*data = (md->lsegwordbuf << 16) | (temp >> 16);
|
|
md->lsegwordbuf = (UWORD)temp;
|
|
md->lseghasword = TRUE;
|
|
} else {
|
|
v = lseg_read_longs(md, 1, data);
|
|
}
|
|
dbg("lseg_read_long %08"PRIx32"\n", *data);
|
|
return v;
|
|
}
|
|
// Read single word from LSEG blocks
|
|
// Internally reads long and buffers second word.
|
|
static BOOL lseg_read_word(struct MountData *md, ULONG *data)
|
|
{
|
|
if (md->lseghasword) {
|
|
*data = md->lsegwordbuf;
|
|
md->lseghasword = FALSE;
|
|
dbg("lseg_read_word 2/2 %08"PRIx32"\n", *data);
|
|
return TRUE;
|
|
}
|
|
ULONG temp;
|
|
BOOL v = lseg_read_longs(md, 1, &temp);
|
|
if (v) {
|
|
md->lseghasword = TRUE;
|
|
md->lsegwordbuf = (UWORD)temp;
|
|
*data = temp >> 16;
|
|
}
|
|
dbg("lseg_read_word 1/2 %08"PRIx32"\n", *data);
|
|
return v;
|
|
}
|
|
|
|
struct RelocHunk
|
|
{
|
|
ULONG hunkSize;
|
|
ULONG *hunkData;
|
|
};
|
|
|
|
// Filesystem relocator
|
|
static APTR fsrelocate(struct MountData *md)
|
|
{
|
|
struct ExecBase *SysBase = md->SysBase;
|
|
ULONG data;
|
|
struct RelocHunk *relocHunks;
|
|
LONG firstHunk, lastHunk;
|
|
LONG totalHunks;
|
|
WORD hunkCnt;
|
|
WORD ret = 0;
|
|
APTR firstProcessedHunk = NULL;
|
|
|
|
if (!lseg_read_long(md, &data)) {
|
|
return NULL;
|
|
}
|
|
if (data != HUNK_HEADER) {
|
|
return NULL;
|
|
}
|
|
// Read the size of a resident library name. This should
|
|
// never be != 0.
|
|
if (!lseg_read_long(md, &data) || data != 0) {
|
|
return NULL;
|
|
}
|
|
// Read the size of the hunk table, which should be > 0.
|
|
// Note that this number may be larger than the
|
|
// difference between the last and the first hunk + 1 for
|
|
// overlay binary files. But then this function does not
|
|
// support overlay binary files.
|
|
if (!lseg_read_long(md, &data) || data <= 0) {
|
|
return NULL;
|
|
}
|
|
// first hunk
|
|
if (!lseg_read_long(md, &firstHunk)) {
|
|
return NULL;
|
|
}
|
|
// last hunk
|
|
if (!lseg_read_long(md, &lastHunk)) {
|
|
return NULL;
|
|
}
|
|
if (firstHunk < 0 || lastHunk < 0 || firstHunk > lastHunk) {
|
|
return NULL;
|
|
}
|
|
totalHunks = lastHunk - firstHunk + 1;
|
|
dbg("first hunk %"PRId32", last hunk %"PRId32"\n", firstHunk, lastHunk);
|
|
relocHunks = AllocMem(totalHunks * sizeof(struct RelocHunk), MEMF_CLEAR);
|
|
if (!relocHunks) {
|
|
return NULL;
|
|
}
|
|
|
|
// Pre-allocate hunks
|
|
ULONG *prevChunk = NULL;
|
|
hunkCnt = 0;
|
|
while (hunkCnt < totalHunks) {
|
|
struct RelocHunk *rh = &relocHunks[hunkCnt];
|
|
ULONG hunkHeadSize;
|
|
ULONG memoryFlags = MEMF_PUBLIC;
|
|
if (!lseg_read_long(md, &hunkHeadSize)) {
|
|
goto end;
|
|
}
|
|
if ((hunkHeadSize & (HUNKF_CHIP | HUNKF_FAST)) == (HUNKF_CHIP | HUNKF_FAST)) {
|
|
if (!lseg_read_long(md, &memoryFlags)) {
|
|
goto end;
|
|
}
|
|
} else if (hunkHeadSize & HUNKF_CHIP) {
|
|
memoryFlags |= MEMF_CHIP;
|
|
}
|
|
hunkHeadSize &= ~(HUNKF_CHIP | HUNKF_FAST);
|
|
rh->hunkSize = hunkHeadSize;
|
|
rh->hunkData = AllocMem((hunkHeadSize + 2) * sizeof(ULONG), memoryFlags | MEMF_CLEAR);
|
|
if (!rh->hunkData) {
|
|
goto end;
|
|
}
|
|
dbg("hunk %"PRId32": ptr %p, size %"PRId32", memory flags %08"PRIx32"\n", hunkCnt + firstHunk, rh->hunkData, hunkHeadSize, memoryFlags);
|
|
rh->hunkData[0] = rh->hunkSize + 2;
|
|
rh->hunkData[1] = MKBADDR(prevChunk);
|
|
prevChunk = &rh->hunkData[1];
|
|
rh->hunkData += 2;
|
|
|
|
if (!firstProcessedHunk) {
|
|
firstProcessedHunk = (APTR)(rh->hunkData - 1);
|
|
}
|
|
hunkCnt++;
|
|
}
|
|
dbg("hunks allocated\n");
|
|
|
|
// Load hunks/relocate
|
|
hunkCnt = 0;
|
|
struct RelocHunk *rh = NULL;
|
|
while (hunkCnt <= totalHunks) {
|
|
ULONG hunkType;
|
|
if (!lseg_read_long(md, &hunkType)) {
|
|
if (hunkCnt >= totalHunks) {
|
|
break; // normal end
|
|
}
|
|
goto end;
|
|
}
|
|
dbg("HUNK %08"PRIx32"\n", hunkType);
|
|
switch(hunkType)
|
|
{
|
|
case HUNK_CODE:
|
|
case HUNK_DATA:
|
|
case HUNK_BSS:
|
|
{
|
|
ULONG hunkSize;
|
|
if (hunkCnt >= totalHunks) {
|
|
goto end; // overflow
|
|
}
|
|
rh = &relocHunks[hunkCnt++];
|
|
if (!lseg_read_long(md, &hunkSize)) {
|
|
goto end;
|
|
}
|
|
if (hunkSize > rh->hunkSize) {
|
|
goto end;
|
|
}
|
|
if (hunkType != HUNK_BSS) {
|
|
if (!lseg_read_longs(md, hunkSize, rh->hunkData)) {
|
|
goto end;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case HUNK_RELOC32:
|
|
case HUNK_RELOC32SHORT:
|
|
{
|
|
ULONG relocCnt, relocHunk;
|
|
if (rh == NULL) {
|
|
goto end;
|
|
}
|
|
for (;;) {
|
|
if (!lseg_read_long(md, &relocCnt)) {
|
|
goto end;
|
|
}
|
|
if (!relocCnt) {
|
|
break;
|
|
}
|
|
if (!lseg_read_long(md, &relocHunk)) {
|
|
goto end;
|
|
}
|
|
relocHunk -= firstHunk;
|
|
if (relocHunk >= totalHunks) {
|
|
goto end;
|
|
}
|
|
dbg("HUNK_RELOC32: relocs %"PRId32" hunk %"PRId32"\n", relocCnt, relocHunk + firstHunk);
|
|
struct RelocHunk *rhr = &relocHunks[relocHunk];
|
|
while (relocCnt != 0) {
|
|
ULONG relocOffset;
|
|
if (hunkType == HUNK_RELOC32SHORT) {
|
|
if (!lseg_read_word(md, &relocOffset)) {
|
|
goto end;
|
|
}
|
|
} else {
|
|
if (!lseg_read_long(md, &relocOffset)) {
|
|
goto end;
|
|
}
|
|
}
|
|
if (relocOffset > (rh->hunkSize - 1) * sizeof(ULONG)) {
|
|
goto end;
|
|
}
|
|
UBYTE *hData = (UBYTE*)rh->hunkData + relocOffset;
|
|
if (relocOffset & 1) {
|
|
// Odd address, 68000/010 support.
|
|
ULONG v = (hData[0] << 24) | (hData[1] << 16) | (hData[2] << 8) | (hData[3] << 0);
|
|
v += (ULONG)rhr->hunkData;
|
|
hData[0] = v >> 24;
|
|
hData[1] = v >> 16;
|
|
hData[2] = v >> 8;
|
|
hData[3] = v >> 0;
|
|
} else {
|
|
*((ULONG*)hData) += (ULONG)rhr->hunkData;
|
|
}
|
|
relocCnt--;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case HUNK_END:
|
|
// do nothing
|
|
if (hunkCnt >= totalHunks) {
|
|
ret = 1; // normal end
|
|
goto end;
|
|
}
|
|
break;
|
|
default:
|
|
dbg("Unexpected HUNK!\n");
|
|
goto end;
|
|
}
|
|
}
|
|
ret = 1;
|
|
|
|
end:
|
|
if (!ret) {
|
|
dbg("reloc failed\n");
|
|
hunkCnt = 0;
|
|
while (hunkCnt < totalHunks) {
|
|
struct RelocHunk *rh = &relocHunks[hunkCnt];
|
|
if (rh->hunkData) {
|
|
FreeMem(rh->hunkData - 2, (rh->hunkSize + 2) * sizeof(ULONG));
|
|
}
|
|
hunkCnt++;
|
|
}
|
|
firstProcessedHunk = NULL;
|
|
} else {
|
|
cacheclear(md);
|
|
dbg("reloc ok, first hunk %p\n", firstProcessedHunk);
|
|
}
|
|
|
|
FreeMem(relocHunks, totalHunks * sizeof(struct RelocHunk));
|
|
|
|
return firstProcessedHunk;
|
|
}
|
|
|
|
// Scan FileSystem.resource, create new if it is not found or existing entry has older version number.
|
|
static struct FileSysEntry *FSHDProcess(struct FileSysHeaderBlock *fshb, ULONG dostype, ULONG version, BOOL newOnly, struct MountData *md)
|
|
{
|
|
struct ExecBase *SysBase = md->SysBase;
|
|
struct FileSysEntry *fse = NULL;
|
|
const UBYTE *creator = md->creator ? md->creator : md->zero;
|
|
const char resourceName[] = "FileSystem.resource";
|
|
|
|
Forbid();
|
|
|
|
struct FileSysResource *fsr = NULL;
|
|
fsr = OpenResource(FSRNAME);
|
|
if (!fsr) {
|
|
// FileSystem.resource didn't exist (KS 1.3), create it.
|
|
fsr = AllocMem(sizeof(struct FileSysResource) + strlen(resourceName) + 1 + strlen(creator) + 1, MEMF_PUBLIC | MEMF_CLEAR);
|
|
if (fsr) {
|
|
|
|
char *FsResName = (UBYTE *)(fsr + 1);
|
|
char *CreatorStr = (UBYTE *)FsResName + (strlen(resourceName) + 1);
|
|
|
|
//char *CreatorStr = (char *)AllocMem(strlen(creator)+1,MEMF_PUBLIC|MEMF_CLEAR);
|
|
//char *FsResName = (char *)AllocMem(strlen(resourceName)+1,MEMF_PUBLIC|MEMF_CLEAR);
|
|
|
|
NewList(&fsr->fsr_FileSysEntries);
|
|
fsr->fsr_Node.ln_Type = NT_RESOURCE;
|
|
strcpy(FsResName, resourceName);
|
|
fsr->fsr_Node.ln_Name = FsResName;
|
|
strcpy(CreatorStr, creator);
|
|
fsr->fsr_Creator = CreatorStr;
|
|
AddTail(&SysBase->ResourceList, &fsr->fsr_Node);
|
|
}
|
|
dbg("FileSystem.resource created %p\n", fsr);
|
|
}
|
|
if (fsr) {
|
|
fse = (struct FileSysEntry*)fsr->fsr_FileSysEntries.lh_Head;
|
|
while (fse->fse_Node.ln_Succ) {
|
|
if (fse->fse_DosType == dostype) {
|
|
if (fse->fse_Version >= version) {
|
|
// FileSystem.resource filesystem is same or newer, don't update
|
|
if (newOnly) {
|
|
dbg("FileSystem.resource scan: %p dostype %08"PRIx32" found, FSRES version %08"PRIx32" >= FSHD version %08"PRIx32"\n", fse, dostype, fse->fse_Version, version);
|
|
fse = NULL;
|
|
}
|
|
goto end;
|
|
}
|
|
}
|
|
fse = (struct FileSysEntry*)fse->fse_Node.ln_Succ;
|
|
}
|
|
|
|
// If the FS wasn't found fse would have been pointing at the last FS in FileSystem.resource
|
|
if (fse->fse_DosType != dostype) fse = NULL;
|
|
|
|
if (fshb && newOnly) {
|
|
fse = AllocMem(sizeof(struct FileSysEntry) + strlen(creator) + 1, MEMF_PUBLIC | MEMF_CLEAR);
|
|
if (fse) {
|
|
// Process patchflags
|
|
ULONG *dstPatch = &fse->fse_Type;
|
|
ULONG *srcPatch = &fshb->fhb_Type;
|
|
ULONG patchFlags = fshb->fhb_PatchFlags;
|
|
while (patchFlags) {
|
|
if ((patchFlags & 1) != 0)
|
|
*dstPatch = *srcPatch;
|
|
dstPatch++;
|
|
srcPatch++;
|
|
patchFlags >>= 1;
|
|
}
|
|
fse->fse_DosType = fshb->fhb_DosType;
|
|
fse->fse_Version = fshb->fhb_Version;
|
|
fse->fse_PatchFlags = fshb->fhb_PatchFlags;
|
|
strcpy((UBYTE*)(fse + 1), creator);
|
|
fse->fse_Node.ln_Name = (UBYTE*)(fse + 1);
|
|
}
|
|
dbg("FileSystem.resource scan: dostype %08"PRIx32" not found or old version: created new\n", dostype);
|
|
}
|
|
}
|
|
end:
|
|
Permit();
|
|
return fse;
|
|
}
|
|
// Add new FileSysEntry to FileSystem.resource or free it if filesystem load failed.
|
|
static void FSHDAdd(struct FileSysEntry *fse, struct MountData *md)
|
|
{
|
|
struct ExecBase *SysBase = md->SysBase;
|
|
if (fse->fse_SegList) {
|
|
Forbid();
|
|
struct FileSysResource *fsr = OpenResource(FSRNAME);
|
|
if (fsr) {
|
|
AddHead(&fsr->fsr_FileSysEntries, &fse->fse_Node);
|
|
dbg("FileSysEntry %p added to FileSystem.resource, dostype %08"PRIx32"\n", fse, fse->fse_DosType);
|
|
fse = NULL;
|
|
}
|
|
Permit();
|
|
}
|
|
if (fse) {
|
|
dbg("FileSysEntry %p freed, dostype %08"PRIx32"\n", fse, fse->fse_DosType);
|
|
FreeMem(fse, sizeof(struct FileSysEntry));
|
|
}
|
|
}
|
|
|
|
// Parse FileSystem Header Blocks, load and relocate filesystem if needed.
|
|
static struct FileSysEntry *ParseFSHD(UBYTE *buf, ULONG block, ULONG dostype, struct MountData *md)
|
|
{
|
|
struct FileSysHeaderBlock *fshb = (struct FileSysHeaderBlock*)buf;
|
|
struct FileSysEntry *fse = NULL;
|
|
|
|
for (;;) {
|
|
if (block == 0xffffffff) {
|
|
break;
|
|
}
|
|
if (!readblock(buf, block, IDNAME_FILESYSHEADER, md)) {
|
|
break;
|
|
}
|
|
dbg("FSHD found, block %"PRIu32", dostype %08"PRIx32", looking for dostype %08"PRIx32"\n", block, fshb->fhb_DosType, dostype);
|
|
if (fshb->fhb_DosType == dostype) {
|
|
dbg("FSHD dostype match found\n");
|
|
fse = FSHDProcess(fshb, dostype, fshb->fhb_Version, TRUE, md);
|
|
if (fse) {
|
|
md->lsegblock = fshb->fhb_SegListBlocks;
|
|
md->lsegbuf = (struct LoadSegBlock*)(buf + md->blocksize);
|
|
md->lseglongs = 0;
|
|
APTR seg = fsrelocate(md);
|
|
fse->fse_SegList = MKBADDR(seg);
|
|
// Add to FileSystem.resource if succeeded, delete entry if failure.
|
|
FSHDAdd(fse, md);
|
|
}
|
|
break;
|
|
}
|
|
block = fshb->fhb_Next;
|
|
}
|
|
if (!fse) {
|
|
fse = FSHDProcess(NULL, dostype, 0, FALSE, md);
|
|
}
|
|
return fse;
|
|
}
|
|
|
|
#if NO_CONFIGDEV
|
|
// Create fake ConfigDev and DiagArea to support autoboot without requiring real autoconfig device.
|
|
static void CreateFakeConfigDev(struct MountData *md)
|
|
{
|
|
struct ExecBase *SysBase = md->SysBase;
|
|
struct ExpansionBase *ExpansionBase = md->ExpansionBase;
|
|
struct ConfigDev *configDev;
|
|
|
|
configDev = AllocConfigDev();
|
|
if (configDev) {
|
|
configDev->cd_BoardAddr = (void*)&entrypoint;
|
|
configDev->cd_BoardSize = (UBYTE*)&entrypoint_end - (UBYTE*)&entrypoint;
|
|
configDev->cd_Rom.er_Type = ERTF_DIAGVALID;
|
|
ULONG bbSize = &bootblock_end - &bootblock;
|
|
ULONG daSize = sizeof(struct DiagArea) + bbSize;
|
|
struct DiagArea *diagArea = AllocMem(daSize, MEMF_CLEAR | MEMF_PUBLIC);
|
|
if (diagArea) {
|
|
diagArea->da_Config = DAC_CONFIGTIME;
|
|
diagArea->da_BootPoint = sizeof(struct DiagArea);
|
|
diagArea->da_Size = (UWORD)daSize;
|
|
copymem(diagArea + 1, &bootblock, bbSize);
|
|
*((ULONG*)&configDev->cd_Rom.er_Reserved0c) = (ULONG)diagArea;
|
|
cacheclear(md);
|
|
}
|
|
md->configDev = configDev;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
struct ParameterPacket
|
|
{
|
|
const UBYTE *dosname;
|
|
const UBYTE *execname;
|
|
ULONG unitnum;
|
|
ULONG flags;
|
|
struct DosEnvec de;
|
|
};
|
|
|
|
static UBYTE ToUpper(UBYTE c)
|
|
{
|
|
if (c >= 'a' || c <= 'z') {
|
|
c |= 0x20;
|
|
}
|
|
return c;
|
|
}
|
|
|
|
// Case-insensitive BSTR string comparison
|
|
static BOOL CompareBSTRNoCase(const UBYTE *src1, const UBYTE *src2)
|
|
{
|
|
UBYTE len1 = *src1++;
|
|
UBYTE len2 = *src2++;
|
|
if (len1 != len2) {
|
|
return FALSE;
|
|
}
|
|
for (UWORD i = 0; i < len1; i++) {
|
|
UBYTE c1 = *src1++;
|
|
UBYTE c2 = *src2++;
|
|
c1 = ToUpper(c1);
|
|
c2 = ToUpper(c2);
|
|
if (c1 != c2) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
// Check for duplicate device names
|
|
static void CheckAndFixDevName(struct MountData *md, UBYTE *bname)
|
|
{
|
|
struct ExecBase *SysBase = md->SysBase;
|
|
|
|
Forbid();
|
|
struct BootNode *bn = (struct BootNode*)md->ExpansionBase->MountList.lh_Head;
|
|
while (bn->bn_Node.ln_Succ) {
|
|
struct DeviceNode *dn = bn->bn_DeviceNode;
|
|
const UBYTE *bname2 = BADDR(dn->dn_Name);
|
|
if (CompareBSTRNoCase(bname, bname2)) {
|
|
UBYTE len = bname[0] > 30 ? 30 : bname[0];
|
|
UBYTE *name = bname + 1;
|
|
dbg("Duplicate device name '%s'\n", name);
|
|
if (len > 2 && name[len - 2] == '.' && name[len - 1] >= '0' && name[len - 1] < '9') {
|
|
// if already ends to .<digit>: increase digit by one
|
|
name[len - 1]++;
|
|
} else {
|
|
// else append .1
|
|
name[len++] = '.';
|
|
name[len++] = '1';
|
|
name[len] = 0;
|
|
bname[0] += 2;
|
|
}
|
|
dbg("-> new device name '%s'\n", name);
|
|
// retry
|
|
bn = (struct BootNode*)md->ExpansionBase->MountList.lh_Head;
|
|
continue;
|
|
}
|
|
bn = (struct BootNode*)bn->bn_Node.ln_Succ;
|
|
}
|
|
Permit();
|
|
}
|
|
|
|
// Add DeviceNode to Expansion MountList.
|
|
static void AddNode(struct PartitionBlock *part, struct ParameterPacket *pp, struct DeviceNode *dn, UBYTE *name, struct MountData *md)
|
|
{
|
|
struct ExecBase *SysBase = md->SysBase;
|
|
struct ExpansionBase *ExpansionBase = md->ExpansionBase;
|
|
struct DosLibrary *DOSBase = md->DOSBase;
|
|
|
|
LONG bootPri = (part->pb_Flags & PBFF_BOOTABLE) ? pp->de.de_BootPri : -128;
|
|
if (ExpansionBase->LibNode.lib_Version >= 37) {
|
|
// KS 2.0+
|
|
if (!md->DOSBase && bootPri > -128) {
|
|
dbg("KS20+ Mounting as bootable: pri %08"PRIx32"\n", bootPri);
|
|
AddBootNode(bootPri, ADNF_STARTPROC, dn, md->configDev);
|
|
} else {
|
|
dbg("KS20+: Mounting as non-bootable\n");
|
|
AddDosNode(bootPri, ADNF_STARTPROC, dn);
|
|
}
|
|
} else {
|
|
// KS 1.3
|
|
if (!md->DOSBase && bootPri > -128) {
|
|
dbg("KS13 Mounting as bootable: pri %08"PRIx32"\n", bootPri);
|
|
// Create and insert bootnode manually.
|
|
struct BootNode *bn = AllocMem(sizeof(struct BootNode), MEMF_CLEAR | MEMF_PUBLIC);
|
|
if (bn) {
|
|
bn->bn_Node.ln_Type = NT_BOOTNODE;
|
|
bn->bn_Node.ln_Pri = (BYTE)bootPri;
|
|
bn->bn_Node.ln_Name = (UBYTE*)md->configDev;
|
|
bn->bn_DeviceNode = dn;
|
|
Forbid();
|
|
Enqueue(&md->ExpansionBase->MountList, &bn->bn_Node);
|
|
Permit();
|
|
}
|
|
} else {
|
|
dbg("KS13: Mounting as non-bootable\n");
|
|
AddDosNode(bootPri, 0, dn);
|
|
if (md->DOSBase) {
|
|
// KS 1.3 ADNF_STARTPROC is not supported
|
|
// need to use DeviceProc() to start the filesystem process.
|
|
UWORD len = strlen(name);
|
|
name[len++] = ':';
|
|
name[len] = 0;
|
|
void *mp = DeviceProc(name);
|
|
dbg("DeviceProc() returned %p\n", mp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Parse PART block, mount drive.
|
|
static ULONG ParsePART(UBYTE *buf, ULONG block, ULONG filesysblock, struct MountData *md)
|
|
{
|
|
struct ExecBase *SysBase = md->SysBase;
|
|
struct ExpansionBase *ExpansionBase = md->ExpansionBase;
|
|
struct PartitionBlock *part = (struct PartitionBlock*)buf;
|
|
ULONG nextpartblock = 0xffffffff;
|
|
|
|
if (!readblock(buf, block, IDNAME_PARTITION, md)) {
|
|
return nextpartblock;
|
|
}
|
|
dbg("PART found, block %"PRIu32"\n", block);
|
|
nextpartblock = part->pb_Next;
|
|
if (!(part->pb_Flags & PBFF_NOMOUNT)) {
|
|
struct ParameterPacket *pp = AllocMem(sizeof(struct ParameterPacket), MEMF_PUBLIC | MEMF_CLEAR);
|
|
if (pp) {
|
|
UBYTE len;
|
|
copymem(&pp->de, &part->pb_Environment, (part->pb_Environment[0] + 1) * sizeof(ULONG));
|
|
struct FileSysEntry *fse = ParseFSHD(buf + md->blocksize, filesysblock, pp->de.de_DosType, md);
|
|
pp->execname = md->devicename;
|
|
pp->unitnum = md->unitnum;
|
|
pp->dosname = part->pb_DriveName + 1;
|
|
len=(*part->pb_DriveName) > 30 ? 30 : (*part->pb_DriveName);
|
|
part->pb_DriveName[len + 1] = 0;
|
|
dbg("PART '%s'\n", pp->dosname);
|
|
CheckAndFixDevName(md, part->pb_DriveName);
|
|
struct DeviceNode *dn = MakeDosNode(pp);
|
|
if (dn) {
|
|
if (fse) {
|
|
// Process PatchFlags
|
|
ULONG *dstPatch = &dn->dn_Type;
|
|
ULONG *srcPatch = &fse->fse_Type;
|
|
ULONG patchFlags = fse->fse_PatchFlags;
|
|
while (patchFlags) {
|
|
if (patchFlags & 1) {
|
|
*dstPatch = *srcPatch;
|
|
}
|
|
patchFlags >>= 1;
|
|
srcPatch++;
|
|
dstPatch++;
|
|
}
|
|
dbg("Mounting partition\n");
|
|
#if NO_CONFIGDEV
|
|
if (!md->configDev && !md->DOSBase) {
|
|
CreateFakeConfigDev(md);
|
|
}
|
|
#endif
|
|
}
|
|
AddNode(part, pp, dn, part->pb_DriveName + 1, md);
|
|
md->ret++;
|
|
} else {
|
|
dbg("Device node creation failed\n");
|
|
}
|
|
FreeMem(pp, sizeof(struct ParameterPacket));
|
|
}
|
|
}
|
|
return nextpartblock;
|
|
}
|
|
|
|
// Scan PART blocks
|
|
static LONG ParseRDSK(UBYTE *buf, struct MountData *md)
|
|
{
|
|
struct RigidDiskBlock *rdb = (struct RigidDiskBlock*)buf;
|
|
ULONG partblock = rdb->rdb_PartitionList;
|
|
ULONG filesysblock = rdb->rdb_FileSysHeaderList;
|
|
ULONG flags = rdb->rdb_Flags;
|
|
for (;;) {
|
|
if (partblock == 0xffffffff) {
|
|
break;
|
|
}
|
|
partblock = ParsePART(buf, partblock, filesysblock, md);
|
|
}
|
|
md->wasLastDev = (flags & RDBFF_LAST) != 0;
|
|
return md->ret;
|
|
}
|
|
|
|
// Search for RDB
|
|
static LONG ScanRDSK(struct MountData *md)
|
|
{
|
|
struct ExecBase *SysBase = md->SysBase;
|
|
LONG ret = -1;
|
|
for (UWORD i = 0; i < RDB_LOCATION_LIMIT; i++) {
|
|
if (readblock(md->buf, i, 0xffffffff, md)) {
|
|
struct RigidDiskBlock *rdb = (struct RigidDiskBlock*)md->buf;
|
|
if (rdb->rdb_ID == IDNAME_RIGIDDISK) {
|
|
dbg("RDB found, block %"PRIu32"\n", i);
|
|
ret = ParseRDSK(md->buf, md);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
md->request->iotd_Req.io_Command = TD_MOTOR;
|
|
md->request->iotd_Req.io_Length = 0;
|
|
DoIO((struct IORequest*)md->request);
|
|
return ret;
|
|
}
|
|
#if CDBOOT
|
|
static struct FileSysEntry *scan_filesystems(void)
|
|
{
|
|
struct FileSysEntry *fse, *cdfs=NULL;
|
|
|
|
/* NOTE - you should actually be in a Forbid while accessing any
|
|
* system list for which no other method of arbitration is available.
|
|
* However, for this example we will be printing the information
|
|
* (which would break a Forbid anyway) so we won't Forbid.
|
|
* In real life, you should Forbid, copy the information you need,
|
|
* Permit, then print the info.
|
|
*/
|
|
if (!(FileSysResBase = (struct FileSysResource *)OpenResource(FSRNAME))) {
|
|
dbg("Cannot open %s\n",FSRNAME);
|
|
} else {
|
|
dbg("DosType Version Creator\n");
|
|
dbg("------------------------------------------------\n");
|
|
for ( fse = (struct FileSysEntry *)FileSysResBase->fsr_FileSysEntries.lh_Head;
|
|
fse->fse_Node.ln_Succ;
|
|
fse = (struct FileSysEntry *)fse->fse_Node.ln_Succ) {
|
|
#ifdef DEBUG_MOUNTER
|
|
int x;
|
|
for (x=24; x>=8; x-=8)
|
|
putchar((fse->fse_DosType >> x) & 0xFF);
|
|
|
|
putchar((fse->fse_DosType & 0xFF) < 0x30
|
|
? (fse->fse_DosType & 0xFF) + 0x30
|
|
: (fse->fse_DosType & 0xFF));
|
|
#endif
|
|
dbg(" %s%d",(fse->fse_Version >> 16)<10 ? " " : "", (fse->fse_Version >> 16));
|
|
dbg(".%d%s",(fse->fse_Version & 0xFFFF), (fse->fse_Version & 0xFFFF)<10 ? " " : "");
|
|
dbg(" %s",fse->fse_Node.ln_Name);
|
|
|
|
if (fse->fse_DosType==0x43443031) {
|
|
cdfs=fse;
|
|
#ifndef ALL_FILESYSTEMS
|
|
break;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
}
|
|
return cdfs;
|
|
}
|
|
|
|
// Search for Bootable CDROM
|
|
static LONG ScanCDROM(struct MountData *md)
|
|
{
|
|
struct ExpansionBase *ExpansionBase = md->ExpansionBase;
|
|
struct FileSysEntry *fse=NULL;
|
|
char dosName[] = "CD0";
|
|
static unsigned int cnt = 0;
|
|
LONG bootPri;
|
|
|
|
// "CDTV" or "AMIGA BOOT"?
|
|
if (CheckPVD((struct IOStdReq *)md->request)) {
|
|
bootPri = 2; // Yes, give priority
|
|
} else {
|
|
bootPri = -1; // May not be a boot disk, lower priority than HDD
|
|
}
|
|
|
|
struct ParameterPacket pp;
|
|
|
|
memset(&pp,0,sizeof(struct ParameterPacket));
|
|
|
|
pp.dosname = dosName;
|
|
pp.execname = md->devicename;
|
|
pp.unitnum = md->unitnum;
|
|
pp.de.de_TableSize = sizeof(struct DosEnvec);
|
|
pp.de.de_SizeBlock = 2048 >> 2;
|
|
pp.de.de_Surfaces = 1;
|
|
pp.de.de_SectorPerBlock = 1;
|
|
pp.de.de_BlocksPerTrack = 1;
|
|
pp.de.de_NumBuffers = 5;
|
|
pp.de.de_BufMemType = MEMF_ANY|MEMF_CLEAR;
|
|
pp.de.de_MaxTransfer = 0x100000;
|
|
pp.de.de_Mask = 0x7FFFFFFE;
|
|
pp.de.de_DosType = 0x43443031; // CD01
|
|
pp.de.de_BootPri = bootPri;
|
|
|
|
fse=scan_filesystems();
|
|
if (!fse) {
|
|
// printf("Could not load filesystem\n");
|
|
return -1;
|
|
}
|
|
|
|
dosName[2]='0' + cnt;
|
|
struct DeviceNode *node = MakeDosNode(&pp);
|
|
if (!node) {
|
|
// printf("Could not create DosNode\n");
|
|
return -1;
|
|
}
|
|
|
|
// TODO some consistency check that this is actually
|
|
// a bootable Amiga CDROM
|
|
// - iso toc
|
|
// - CDTV or CD32 disk
|
|
|
|
// Process PatchFlags.
|
|
ULONG *dstPatch = &node->dn_Type;
|
|
ULONG *srcPatch = &fse->fse_Type;
|
|
ULONG patchFlags = fse->fse_PatchFlags;
|
|
while (patchFlags) {
|
|
if (patchFlags & 1) {
|
|
*dstPatch = *srcPatch;
|
|
}
|
|
patchFlags >>= 1;
|
|
srcPatch++;
|
|
dstPatch++;
|
|
}
|
|
|
|
AddBootNode(bootPri, ADNF_STARTPROC, node, md->configDev);
|
|
cnt++;
|
|
|
|
return 1;
|
|
}
|
|
|
|
#endif
|
|
|
|
// Mount drives
|
|
LONG MountDrive(struct MountStruct *ms)
|
|
{
|
|
LONG ret = -1;
|
|
ULONG uidx = 0;
|
|
int blockSize = 0;
|
|
struct UnitStruct *unit;
|
|
struct MsgPort *port = NULL;
|
|
struct IOExtTD *request = NULL;
|
|
struct ExpansionBase *ExpansionBase;
|
|
struct ExecBase *SysBase = ms->SysBase;
|
|
|
|
dbg("Starting..\n");
|
|
ExpansionBase = (struct ExpansionBase*)OpenLibrary("expansion.library", 34);
|
|
if (ExpansionBase) {
|
|
struct MountData *md = AllocMem(sizeof(struct MountData), MEMF_CLEAR | MEMF_PUBLIC);
|
|
if (md) {
|
|
md->DOSBase = (struct DosLibrary*)OpenLibrary("dos.library", 34);
|
|
md->SysBase = SysBase;
|
|
md->ExpansionBase = ExpansionBase;
|
|
dbg("SysBase=%p ExpansionBase=%p DosBase=%p\n", md->SysBase, md->ExpansionBase, md->DOSBase);
|
|
md->creator = ms->creatorName;
|
|
port = W_CreateMsgPort(SysBase);
|
|
if(port) {
|
|
request = (struct IOExtTD*)W_CreateIORequest(port, sizeof(struct IOExtTD), SysBase);
|
|
if(request) {
|
|
UWORD unitNumCnt = ms->numUnits;
|
|
while (unitNumCnt-- > 0) {
|
|
unit = &ms->Units[uidx++];
|
|
dbg("OpenDevice('%s', %"PRId32", %p, 0)\n", ms->deviceName, unit->unitNum, request);
|
|
UBYTE err = OpenDevice(ms->deviceName, unit->unitNum, (struct IORequest*)request, 0);
|
|
if (err == 0) {
|
|
if ((blockSize = GetBlockSize((struct IOStdReq *)request)) > 0) {
|
|
ret = -1;
|
|
md->request = request;
|
|
md->devicename = ms->deviceName;
|
|
md->unitnum = unit->unitNum;
|
|
md->blocksize = blockSize;
|
|
md->configDev = unit->configDev;
|
|
#if CDBOOT
|
|
if (unit->deviceType == DG_CDROM) {
|
|
ret = ScanCDROM(md);
|
|
} else {
|
|
ret = ScanRDSK(md);
|
|
}
|
|
#else
|
|
ret = ScanRDSK(md);
|
|
#endif
|
|
CloseDevice((struct IORequest*)request);
|
|
|
|
#ifndef NO_RDBLAST
|
|
if (md->wasLastDev) {
|
|
dbg("RDBFF_LAST exit\n");
|
|
break;
|
|
}
|
|
#endif
|
|
} else {
|
|
dbg("Couldn't get block size\n");
|
|
}
|
|
} else {
|
|
dbg("OpenDevice(%s,%"PRId32") failed: %"PRId32"\n", ms->deviceName, unit->unitNum, (BYTE)err);
|
|
}
|
|
}
|
|
W_DeleteIORequest(request, SysBase);
|
|
}
|
|
W_DeleteMsgPort(port, SysBase);
|
|
}
|
|
if (md->DOSBase) {
|
|
CloseLibrary(&md->DOSBase->dl_lib);
|
|
}
|
|
FreeMem(md, sizeof(struct MountData));
|
|
}
|
|
CloseLibrary(&ExpansionBase->LibNode);
|
|
}
|
|
dbg("Exit code %"PRId32"\n", ret);
|
|
return ret;
|
|
} |