mirror of
https://github.com/LIV2/lide.device.git
synced 2025-12-06 00:32:45 +00:00
Compare commits
13 Commits
8b144018e5
...
89e3b82f6c
| Author | SHA1 | Date | |
|---|---|---|---|
| 89e3b82f6c | |||
| 8f3e51db7a | |||
| 9acc2025c3 | |||
| c3a7d12653 | |||
| 6f1d844802 | |||
| 19307ccdac | |||
| 1cf84db951 | |||
| 244e137d68 | |||
| 6696cadfd2 | |||
| 657151b6e8 | |||
| e1fa8190d4 | |||
| af8d03e0b9 | |||
| 972c6f2c11 |
1
.github/workflows/release.yml
vendored
1
.github/workflows/release.yml
vendored
@ -17,7 +17,6 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.ACCESS_TOKEN }}
|
||||
submodules: true
|
||||
|
||||
- name: Build
|
||||
|
||||
4
Makefile
4
Makefile
@ -11,7 +11,7 @@ export BUILD_DATE
|
||||
export GIT_REF
|
||||
|
||||
CC=m68k-amigaos-gcc
|
||||
CFLAGS+=-nostartfiles -nostdlib -mcpu=68000 -Wall -Wno-multichar -Wno-pointer-sign -Wno-attributes -Wno-unused-value -s -Os -fomit-frame-pointer -DCDBOOT=1 -DNO_RDBLAST=1
|
||||
CFLAGS+=-nostartfiles -nostdlib -mcpu=68000 -Wall -Wno-multichar -Wno-pointer-sign -Wno-unused-value -s -Os -fomit-frame-pointer -DCDBOOT=1 -DNO_RDBLAST=1
|
||||
CFLAGS+=-DGIT_REF=$(GIT_REF) -DBUILD_DATE=$(BUILD_DATE)
|
||||
LDFLAGS=-lgcc -lc
|
||||
AS=m68k-amigaos-as
|
||||
@ -71,7 +71,7 @@ OBJ = device.o \
|
||||
scsi.o \
|
||||
idetask.o \
|
||||
lide_alib.o \
|
||||
mounter.o \
|
||||
mounter/mounter.o \
|
||||
debug.o
|
||||
|
||||
ASMOBJ = endskip.o
|
||||
|
||||
100
ata.c
100
ata.c
@ -34,7 +34,7 @@ static BYTE write_taskfile_chs(struct IDEUnit *unit, UBYTE command, ULONG lba, U
|
||||
*
|
||||
* @param unit Pointer to an IDEUnit struct
|
||||
*/
|
||||
static void __attribute__((always_inline)) ata_status_reg_delay(struct IDEUnit *unit) {
|
||||
static void ata_status_reg_delay(struct IDEUnit *unit) {
|
||||
asm volatile (
|
||||
".rep 4 \n\t"
|
||||
"tst.l (%0) \n\t" // Use tst.l so we don't need to save/restore some other register
|
||||
@ -68,7 +68,7 @@ static void ata_save_error(struct IDEUnit *unit) {
|
||||
* @param unit Pointer to an IDEUnit struct
|
||||
* @returns True if error is indicated
|
||||
*/
|
||||
static bool __attribute__((always_inline)) ata_check_error(struct IDEUnit *unit) {
|
||||
static bool ata_check_error(struct IDEUnit *unit) {
|
||||
return (*unit->drive.status_command & (ata_flag_error | ata_flag_df));
|
||||
}
|
||||
|
||||
@ -160,7 +160,7 @@ bool ata_select(struct IDEUnit *unit, UBYTE select, bool wait)
|
||||
bool changed = false;
|
||||
volatile UBYTE *shadowDevHead = unit->shadowDevHead;
|
||||
|
||||
if (!unit->lba) select &= ~(0x40);
|
||||
if (!unit->flags.lba) select &= ~(0x40);
|
||||
|
||||
if (*shadowDevHead == select) {
|
||||
return false;
|
||||
@ -193,7 +193,7 @@ bool ata_select(struct IDEUnit *unit, UBYTE select, bool wait)
|
||||
*/
|
||||
bool ata_identify(struct IDEUnit *unit, UWORD *buffer)
|
||||
{
|
||||
UBYTE drvSel = (unit->primary) ? 0xE0 : 0xF0; // Select drive
|
||||
UBYTE drvSel = (unit->flags.primary) ? 0xE0 : 0xF0; // Select drive
|
||||
|
||||
ata_select(unit,drvSel,false);
|
||||
|
||||
@ -342,41 +342,39 @@ void ata_set_xfer(struct IDEUnit *unit, enum xfer method) {
|
||||
*
|
||||
* Initialize a unit, check if it is there and responding
|
||||
* @param unit Pointer to an IDEUnit struct
|
||||
* @param base Base address of the drive registers
|
||||
* @returns false on error
|
||||
*/
|
||||
bool ata_init_unit(struct IDEUnit *unit) {
|
||||
bool ata_init_unit(struct IDEUnit *unit, void *base) {
|
||||
struct ExecBase *SysBase = unit->SysBase;
|
||||
|
||||
unit->cylinders = 0;
|
||||
unit->heads = 0;
|
||||
unit->sectorsPerTrack = 0;
|
||||
unit->blockSize = 0;
|
||||
unit->present = false;
|
||||
unit->mediumPresent = false;
|
||||
unit->cylinders = 0;
|
||||
unit->heads = 0;
|
||||
unit->sectorsPerTrack = 0;
|
||||
unit->blockSize = 0;
|
||||
unit->flags.present = false;
|
||||
unit->flags.mediumPresent = false;
|
||||
|
||||
ULONG offset;
|
||||
UWORD *buf;
|
||||
bool dev_found = false;
|
||||
|
||||
unit->drive.data = (UWORD*) (base + ata_reg_data);
|
||||
unit->drive.error_features = (UBYTE*) (base + ata_reg_error);
|
||||
unit->drive.sectorCount = (UBYTE*) (base + ata_reg_sectorCount);
|
||||
unit->drive.lbaLow = (UBYTE*) (base + ata_reg_lbaLow);
|
||||
unit->drive.lbaMid = (UBYTE*) (base + ata_reg_lbaMid);
|
||||
unit->drive.lbaHigh = (UBYTE*) (base + ata_reg_lbaHigh);
|
||||
unit->drive.devHead = (UBYTE*) (base + ata_reg_devHead);
|
||||
unit->drive.status_command = (UBYTE*) (base + ata_reg_status);
|
||||
|
||||
offset = (unit->channel == 0) ? CHANNEL_0 : CHANNEL_1;
|
||||
|
||||
unit->drive.data = (UWORD*) ((void *)unit->cd->cd_BoardAddr + offset + ata_reg_data);
|
||||
unit->drive.error_features = (UBYTE*) ((void *)unit->cd->cd_BoardAddr + offset + ata_reg_error);
|
||||
unit->drive.sectorCount = (UBYTE*) ((void *)unit->cd->cd_BoardAddr + offset + ata_reg_sectorCount);
|
||||
unit->drive.lbaLow = (UBYTE*) ((void *)unit->cd->cd_BoardAddr + offset + ata_reg_lbaLow);
|
||||
unit->drive.lbaMid = (UBYTE*) ((void *)unit->cd->cd_BoardAddr + offset + ata_reg_lbaMid);
|
||||
unit->drive.lbaHigh = (UBYTE*) ((void *)unit->cd->cd_BoardAddr + offset + ata_reg_lbaHigh);
|
||||
unit->drive.devHead = (UBYTE*) ((void *)unit->cd->cd_BoardAddr + offset + ata_reg_devHead);
|
||||
unit->drive.status_command = (UBYTE*) ((void *)unit->cd->cd_BoardAddr + offset + ata_reg_status);
|
||||
|
||||
*unit->shadowDevHead = *unit->drive.devHead = (unit->primary) ? 0xE0 : 0xF0; // Select drive
|
||||
*unit->shadowDevHead = *unit->drive.devHead = (unit->flags.primary) ? 0xE0 : 0xF0; // Select drive
|
||||
|
||||
enum xfer method = ata_autoselect_xfer(unit);
|
||||
ata_set_xfer(unit,method);
|
||||
|
||||
for (int i=0; i<(8*NEXT_REG); i+=NEXT_REG) {
|
||||
// Check if the bus is floating (D7/6 pulled-up with resistors)
|
||||
if ((i != ata_reg_devHead) && (*((volatile UBYTE *)unit->cd->cd_BoardAddr + offset + i) & 0xC0) != 0xC0) {
|
||||
if ((i != ata_reg_devHead) && (*((volatile UBYTE *)base + i) & 0xC0) != 0xC0) {
|
||||
dev_found = true;
|
||||
Trace("INIT: Unit base: %08lx; Drive base %08lx\n",unit, unit->drive);
|
||||
break;
|
||||
@ -395,20 +393,20 @@ bool ata_init_unit(struct IDEUnit *unit) {
|
||||
if (ata_identify(unit,buf) == true) {
|
||||
Info("INIT: ATA Drive found!\n");
|
||||
|
||||
unit->lba = (buf[ata_identify_capabilities] & ata_capability_lba) != 0;
|
||||
unit->cylinders = buf[ata_identify_cylinders];
|
||||
unit->heads = buf[ata_identify_heads];
|
||||
unit->sectorsPerTrack = buf[ata_identify_sectors];
|
||||
unit->blockSize = 512;
|
||||
unit->logicalSectors = buf[ata_identify_logical_sectors+1] << 16 | buf[ata_identify_logical_sectors];
|
||||
unit->blockShift = 0;
|
||||
unit->mediumPresent = true;
|
||||
unit->multipleCount = buf[ata_identify_multiple] & 0xFF;
|
||||
unit->flags.lba = (buf[ata_identify_capabilities] & ata_capability_lba) != 0;
|
||||
unit->cylinders = buf[ata_identify_cylinders];
|
||||
unit->heads = buf[ata_identify_heads];
|
||||
unit->sectorsPerTrack = buf[ata_identify_sectors];
|
||||
unit->blockSize = 512;
|
||||
unit->logicalSectors = buf[ata_identify_logical_sectors+1] << 16 | buf[ata_identify_logical_sectors];
|
||||
unit->blockShift = 0;
|
||||
unit->flags.mediumPresent = true;
|
||||
unit->multipleCount = buf[ata_identify_multiple] & 0xFF;
|
||||
|
||||
if (unit->multipleCount > 0 && (ata_set_multiple(unit,unit->multipleCount) == 0)) {
|
||||
unit->xferMultiple = true;
|
||||
unit->flags.xferMultiple = true;
|
||||
} else {
|
||||
unit->xferMultiple = false;
|
||||
unit->flags.xferMultiple = false;
|
||||
unit->multipleCount = 1;
|
||||
}
|
||||
|
||||
@ -420,13 +418,13 @@ bool ata_init_unit(struct IDEUnit *unit) {
|
||||
goto ident_failed;
|
||||
}
|
||||
|
||||
unit->lba48 = true;
|
||||
unit->flags.lba48 = true;
|
||||
Info("INIT: Drive supports LBA48 mode \n");
|
||||
unit->logicalSectors = (buf[ata_identify_lba48_sectors + 1] << 16 |
|
||||
buf[ata_identify_lba48_sectors]);
|
||||
unit->write_taskfile = &write_taskfile_lba48;
|
||||
|
||||
} else if (unit->lba == true) {
|
||||
} else if (unit->flags.lba == true) {
|
||||
// LBA-28 up to 127GB
|
||||
unit->write_taskfile = &write_taskfile_lba;
|
||||
|
||||
@ -464,7 +462,7 @@ bool ata_init_unit(struct IDEUnit *unit) {
|
||||
Info("INIT: ATAPI Drive found!\n");
|
||||
|
||||
unit->deviceType = (buf[0] >> 8) & 0x1F;
|
||||
unit->atapi = true;
|
||||
unit->flags.atapi = true;
|
||||
|
||||
atapi_test_unit_ready(unit,true); // Clear the Unit attention check condition
|
||||
} else {
|
||||
@ -476,14 +474,14 @@ ident_failed:
|
||||
}
|
||||
}
|
||||
|
||||
if (unit->atapi == false && unit->blockSize == 0) {
|
||||
if (unit->flags.atapi == false && unit->blockSize == 0) {
|
||||
Warn("INIT: Error! blockSize is 0\n");
|
||||
if (buf) FreeMem(buf,512);
|
||||
return false;
|
||||
}
|
||||
|
||||
Info("INIT: Blockshift: %ld\n",unit->blockShift);
|
||||
unit->present = true;
|
||||
unit->flags.present = true;
|
||||
|
||||
Info("INIT: LBAs %ld Blocksize: %ld\n",unit->logicalSectors,unit->blockSize);
|
||||
|
||||
@ -500,7 +498,7 @@ ident_failed:
|
||||
* @return non-zero on error
|
||||
*/
|
||||
bool ata_set_multiple(struct IDEUnit *unit, BYTE multiple) {
|
||||
UBYTE drvSel = (unit->primary) ? 0xE0 : 0xF0; // Select drive
|
||||
UBYTE drvSel = (unit->flags.primary) ? 0xE0 : 0xF0; // Select drive
|
||||
|
||||
ata_select(unit,drvSel,true);
|
||||
|
||||
@ -552,10 +550,10 @@ BYTE ata_read(void *buffer, ULONG lba, ULONG count, struct IDEUnit *unit) {
|
||||
UBYTE multipleCount = unit->multipleCount;
|
||||
volatile void *dataRegister = unit->drive.data;
|
||||
|
||||
if (unit->lba48) {
|
||||
if (unit->flags.lba48) {
|
||||
command = ATA_CMD_READ_MULTIPLE_EXT;
|
||||
} else {
|
||||
command = (unit->xferMultiple) ? ATA_CMD_READ_MULTIPLE : ATA_CMD_READ;
|
||||
command = (unit->flags.xferMultiple) ? ATA_CMD_READ_MULTIPLE : ATA_CMD_READ;
|
||||
}
|
||||
|
||||
ata_xfer_func ata_xfer;
|
||||
@ -567,7 +565,7 @@ BYTE ata_read(void *buffer, ULONG lba, ULONG count, struct IDEUnit *unit) {
|
||||
ata_xfer = unit->read_fast;
|
||||
}
|
||||
|
||||
UBYTE drvSel = (unit->primary) ? 0xE0 : 0xF0;
|
||||
UBYTE drvSel = (unit->flags.primary) ? 0xE0 : 0xF0;
|
||||
|
||||
ata_select(unit,drvSel,true);
|
||||
|
||||
@ -641,10 +639,10 @@ BYTE ata_write(void *buffer, ULONG lba, ULONG count, struct IDEUnit *unit) {
|
||||
UBYTE multipleCount = unit->multipleCount;
|
||||
volatile void *dataRegister = unit->drive.data;
|
||||
|
||||
if (unit->lba48) {
|
||||
if (unit->flags.lba48) {
|
||||
command = ATA_CMD_WRITE_MULTIPLE_EXT;
|
||||
} else {
|
||||
command = (unit->xferMultiple) ? ATA_CMD_WRITE_MULTIPLE : ATA_CMD_WRITE;
|
||||
command = (unit->flags.xferMultiple) ? ATA_CMD_WRITE_MULTIPLE : ATA_CMD_WRITE;
|
||||
}
|
||||
|
||||
ata_xfer_func ata_xfer;
|
||||
@ -656,7 +654,7 @@ BYTE ata_write(void *buffer, ULONG lba, ULONG count, struct IDEUnit *unit) {
|
||||
ata_xfer = unit->write_fast;
|
||||
}
|
||||
|
||||
UBYTE drvSel = (unit->primary) ? 0xE0 : 0xF0;
|
||||
UBYTE drvSel = (unit->flags.primary) ? 0xE0 : 0xF0;
|
||||
|
||||
ata_select(unit,drvSel,true);
|
||||
|
||||
@ -760,7 +758,7 @@ static BYTE write_taskfile_chs(struct IDEUnit *unit, UBYTE command, ULONG lba, U
|
||||
if (!ata_wait_ready(unit,ATA_RDY_WAIT_COUNT))
|
||||
return HFERR_SelTimeout;
|
||||
|
||||
devHead = ((unit->primary) ? 0xA0 : 0xB0) | (head & 0x0F);
|
||||
devHead = ((unit->flags.primary) ? 0xA0 : 0xB0) | (head & 0x0F);
|
||||
|
||||
*unit->shadowDevHead = devHead;
|
||||
*unit->drive.devHead = devHead;
|
||||
@ -786,7 +784,7 @@ static BYTE write_taskfile_lba(struct IDEUnit *unit, UBYTE command, ULONG lba, U
|
||||
if (!ata_wait_ready(unit,ATA_RDY_WAIT_COUNT))
|
||||
return HFERR_SelTimeout;
|
||||
|
||||
devHead = ((unit->primary) ? 0xE0 : 0xF0) | ((lba >> 24) & 0x0F);
|
||||
devHead = ((unit->flags.primary) ? 0xE0 : 0xF0) | ((lba >> 24) & 0x0F);
|
||||
|
||||
*unit->shadowDevHead = devHead;
|
||||
*unit->drive.devHead = devHead;
|
||||
@ -920,7 +918,7 @@ BYTE scsi_ata_passthrough(struct IDEUnit *unit, struct SCSICmd *cmd) {
|
||||
|
||||
count += (count & 1); // Ensure byte count is even
|
||||
|
||||
UBYTE drvSel = (unit->primary) ? 0xE0 : 0xF0;
|
||||
UBYTE drvSel = (unit->flags.primary) ? 0xE0 : 0xF0;
|
||||
|
||||
ata_select(unit,drvSel,true);
|
||||
|
||||
|
||||
2
ata.h
2
ata.h
@ -104,7 +104,7 @@ enum xfer_dir {
|
||||
#define ATA_RDY_WAIT_COUNT (ATA_RDY_WAIT_S * 1000 * (1000 / ATA_RDY_WAIT_LOOP_US))
|
||||
|
||||
|
||||
bool ata_init_unit(struct IDEUnit *);
|
||||
bool ata_init_unit(struct IDEUnit *unit, void *base);
|
||||
bool ata_select(struct IDEUnit *unit, UBYTE select, bool wait);
|
||||
bool ata_identify(struct IDEUnit *, UWORD *);
|
||||
bool ata_set_multiple(struct IDEUnit *unit, BYTE multiple);
|
||||
|
||||
16
atapi.c
16
atapi.c
@ -31,7 +31,7 @@
|
||||
*
|
||||
* @param unit Pointer to an IDEUnit struct
|
||||
*/
|
||||
static void __attribute__((always_inline)) atapi_status_reg_delay() {
|
||||
static void atapi_status_reg_delay() {
|
||||
asm volatile (
|
||||
"tst.b 0xBFE001"
|
||||
);
|
||||
@ -158,7 +158,7 @@ static bool atapi_check_ir(struct IDEUnit *unit, UBYTE mask, UBYTE value, UWORD
|
||||
* @param unit Pointer to an IDEUnit struct
|
||||
* @returns True if error is indicated
|
||||
*/
|
||||
static bool __attribute__((always_inline)) atapi_check_error(struct IDEUnit *unit) {
|
||||
static bool atapi_check_error(struct IDEUnit *unit) {
|
||||
atapi_status_reg_delay();
|
||||
return (*unit->drive.status_command & (ata_flag_error | ata_flag_df));
|
||||
}
|
||||
@ -206,7 +206,7 @@ bool atapi_check_signature(struct IDEUnit *unit) {
|
||||
*/
|
||||
bool atapi_identify(struct IDEUnit *unit, UWORD *buffer) {
|
||||
|
||||
UBYTE drvSel = (unit->primary) ? 0xE0 : 0xF0; // Select drive
|
||||
UBYTE drvSel = (unit->flags.primary) ? 0xE0 : 0xF0; // Select drive
|
||||
|
||||
// Only update the devHead register if absolutely necessary to save time
|
||||
ata_select(unit,drvSel,false);
|
||||
@ -410,7 +410,7 @@ BYTE atapi_packet(struct SCSICmd *cmd, struct IDEUnit *unit) {
|
||||
|
||||
cmd->scsi_Actual = 0;
|
||||
|
||||
UBYTE drvSelHead = ((unit->primary) ? 0xE0 : 0xF0);
|
||||
UBYTE drvSelHead = ((unit->flags.primary) ? 0xE0 : 0xF0);
|
||||
|
||||
// Only update the devHead register if absolutely necessary to save time
|
||||
ata_select(unit,drvSelHead,true);
|
||||
@ -1119,14 +1119,14 @@ BYTE atapi_check_wp(struct IDEUnit *unit) {
|
||||
*/
|
||||
bool atapi_update_presence(struct IDEUnit *unit, bool present) {
|
||||
bool ret = false;
|
||||
if (present && unit->mediumPresent == false) {
|
||||
if (present && unit->flags.mediumPresent == false) {
|
||||
unit->changeCount++;
|
||||
unit->mediumPresent = true;
|
||||
unit->flags.mediumPresent = true;
|
||||
atapi_get_capacity(unit);
|
||||
ret = true;
|
||||
} else if (!present && unit->mediumPresent == true) {
|
||||
} else if (!present && unit->flags.mediumPresent == true) {
|
||||
unit->changeCount++;
|
||||
unit->mediumPresent = false;
|
||||
unit->flags.mediumPresent = false;
|
||||
unit->logicalSectors = 0;
|
||||
unit->blockShift = 0;
|
||||
unit->blockSize = 0;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
; reloc.S
|
||||
; Modified from Open Source A4091.device by Stefan Reinauer and Chris Hooper - https://github.com/A4091/a4091-software
|
||||
; Modified from Open Source A4091.device by Stefan Reinauer and Chris Hooper - https://github.com/A4091/a3091-software
|
||||
INCLUDE "exec/memory.i"
|
||||
INCLUDE "lvo/exec_lib.i"
|
||||
|
||||
@ -9,6 +9,12 @@
|
||||
|
||||
NUM_ENTRIES EQU 5
|
||||
|
||||
; Frame pointer offsets
|
||||
PHUNKS EQU -4
|
||||
READHANDLE_TYPE EQU -8
|
||||
READHANDLE_CURRENT EQU -12
|
||||
FP_SIZE EQU READHANDLE_CURRENT
|
||||
|
||||
; API:
|
||||
; Zorro ROM access:
|
||||
; a0: rombase
|
||||
@ -19,6 +25,7 @@ NUM_ENTRIES EQU 5
|
||||
public _relocate
|
||||
_relocate
|
||||
movem.l d1-d7/a0-a6,-(sp)
|
||||
link a4,#FP_SIZE
|
||||
|
||||
bsr InitHandle
|
||||
|
||||
@ -39,7 +46,7 @@ _relocate
|
||||
; Go through hunk header and allocate all segments
|
||||
move.l 4,a6 ; execbase
|
||||
|
||||
move.l pHunks(pc),a2 ; segment pointers
|
||||
move.l PHUNKS(a4),a2 ; segment pointers
|
||||
lea.l 4*NUM_ENTRIES(a2),a3 ; segment lengths
|
||||
.AllocateLoop
|
||||
moveq.l #MEMF_PUBLIC,d1
|
||||
@ -54,7 +61,7 @@ _relocate
|
||||
move.l d0,(a2)+ ; segment pointer
|
||||
dbra d7,.AllocateLoop
|
||||
|
||||
move.l pHunks(pc),a5
|
||||
move.l PHUNKS(a4),a5
|
||||
.HunkLoop
|
||||
move.l (a5),a0 ; current hunk
|
||||
bsr RomFetch32
|
||||
@ -85,6 +92,7 @@ _relocate
|
||||
ENDIF
|
||||
bsr .RelocateCleanup
|
||||
moveq.l #0,d0 ; NULL = Failure
|
||||
unlk a4
|
||||
movem.l (sp)+,d1-d7/a0-a6
|
||||
rts
|
||||
|
||||
@ -129,16 +137,16 @@ _relocate
|
||||
move.l d0,d2 ; num ; number of the hunk the offsets are to point into
|
||||
|
||||
lsl.l #2,d2 ; *4 ; offset from Hunks
|
||||
move.l pHunks(pc),a2
|
||||
move.l PHUNKS(a4),a2
|
||||
add.l d2,a2 ; hunk number num
|
||||
move.l (a2),d3 ; base address of hunk
|
||||
|
||||
.Reloc32Tight
|
||||
bsr RomFetch32
|
||||
; get baseaddr + d0, add d3 to the data there.
|
||||
move.l a0,a4
|
||||
add.l d0,a4
|
||||
add.l d3,(a4)
|
||||
move.l a0,a3
|
||||
add.l d0,a3
|
||||
add.l d3,(a3)
|
||||
dbra d1,.Reloc32Tight
|
||||
|
||||
bra .HunkReloc32
|
||||
@ -158,21 +166,21 @@ _relocate
|
||||
move.l d0,d2 ; num ; number of the hunk the offsets are to point into
|
||||
|
||||
lsl.l #2,d2 ; *4 ; offset from Hunks
|
||||
move.l pHunks(pc),a2
|
||||
move.l PHUNKS(a4),a2
|
||||
add.l d2,a2 ; hunk number num
|
||||
move.l (a2),d3 ; base address of hunk
|
||||
|
||||
.Reloc32ShortTight
|
||||
bsr RomFetch16
|
||||
; get baseaddr + d0, add d3 to the data there.
|
||||
move.l a0,a4
|
||||
add.l d0,a4
|
||||
add.l d3,(a4)
|
||||
move.l a0,a3
|
||||
add.l d0,a3
|
||||
add.l d3,(a3)
|
||||
dbra d1,.Reloc32ShortTight
|
||||
|
||||
bra .HunkReloc32Short
|
||||
.HunkLoopPrep
|
||||
lea ReadHandle(pc),a2
|
||||
lea READHANDLE_CURRENT(a4),a2
|
||||
move.l (a2),d0 ; align pointer to longword
|
||||
addq.l #2,d0 ; in case we had an odd number
|
||||
and.l #$fffffffc,d0 ; of relocations
|
||||
@ -202,17 +210,18 @@ _relocate
|
||||
|
||||
bsr.s CreateSegList
|
||||
|
||||
move.l pHunks(pc),a0
|
||||
move.l PHUNKS(a4),a0
|
||||
move.l (a0),d2
|
||||
subq.l #4,d2
|
||||
|
||||
bsr.s .RelocateCleanup
|
||||
move.l d2,d0
|
||||
unlk a4
|
||||
movem.l (sp)+,d1-d7/a0-a6
|
||||
rts
|
||||
|
||||
.RelocateCleanup
|
||||
move.l pHunks(pc),a1
|
||||
move.l PHUNKS(a4),a1
|
||||
moveq.l #(8*NUM_ENTRIES),d0
|
||||
jsr _LVOFreeMem(a6)
|
||||
rts
|
||||
@ -233,7 +242,7 @@ _relocate
|
||||
; +->| | | | 0| | | | | 0|
|
||||
; +--+--+--+--+ +--+--+--+--+
|
||||
CreateSegList:
|
||||
move.l pHunks(pc),a0
|
||||
move.l PHUNKS(a4),a0
|
||||
|
||||
.NextSeg
|
||||
move.l (a0),a1 ; Hunks[x]
|
||||
@ -269,10 +278,10 @@ RomFetch32
|
||||
|
||||
RomFetch
|
||||
movem.l a0-a1/d1-d3,-(sp)
|
||||
lea ReadHandle(pc),a1
|
||||
lea READHANDLE_CURRENT(a4),a1
|
||||
move.l (a1),a0
|
||||
|
||||
tst.l 4(a1) ; access type Zorro?
|
||||
tst.l READHANDLE_TYPE(a4) ; access type Zorro?
|
||||
bne.s .RomFetchZ
|
||||
|
||||
cmp.b #3,d0
|
||||
@ -310,7 +319,7 @@ RomFetch
|
||||
rts
|
||||
|
||||
InitHandle
|
||||
; initialize readhandle to beginning of device driver
|
||||
; initialize READHANDLE_CURRENT to beginning of device driver
|
||||
; ROM_OFFSET needs to be multiplied by 4 because of the
|
||||
; nibble mapped nature of the AutoConfig ROM.
|
||||
; ROM_ADDRESS is passed in a0
|
||||
@ -320,24 +329,15 @@ InitHandle
|
||||
ENDIF
|
||||
|
||||
add.l d0,a0
|
||||
lea ReadHandle(pc),a1
|
||||
move.l a0,(a1) ; memory location passed in a0
|
||||
move.l d0,4(a1) ; Set access type: 0 = memory, Zorro otherwise
|
||||
move.l a0,READHANDLE_CURRENT(a4) ; memory location passed in a0
|
||||
move.l d0,READHANDLE_TYPE(a4) ; Set access type: 0 = memory, Zorro otherwise
|
||||
|
||||
moveq.l #(8*NUM_ENTRIES),d0
|
||||
move.l #MEMF_PUBLIC|MEMF_CLEAR,d1
|
||||
jsr _LVOAllocMem(a6)
|
||||
lea pHunks(pc),a1
|
||||
move.l d0,(a1)
|
||||
move.l d0,PHUNKS(a4)
|
||||
rts
|
||||
|
||||
ReadHandle
|
||||
dc.l 0 ; Current address
|
||||
dc.l 0 ; 0=memory, otherwise Zorro
|
||||
|
||||
pHunks
|
||||
dc.l 0
|
||||
|
||||
IFD HAVE_ERRNO
|
||||
public _rErrno
|
||||
_rErrno
|
||||
|
||||
222
device.c
222
device.c
@ -8,6 +8,7 @@
|
||||
#include <exec/errors.h>
|
||||
#include <exec/execbase.h>
|
||||
#include <exec/resident.h>
|
||||
#include <hardware/cia.h>
|
||||
#include <proto/exec.h>
|
||||
#include <proto/expansion.h>
|
||||
#include <resources/filesysres.h>
|
||||
@ -21,9 +22,9 @@
|
||||
#include "idetask.h"
|
||||
#include "newstyle.h"
|
||||
#include "td64.h"
|
||||
#include "mounter.h"
|
||||
#include "debug.h"
|
||||
#include "lide_alib.h"
|
||||
#include "mounter/mounter.h"
|
||||
|
||||
#ifdef NO_AUTOCONFIG
|
||||
extern UBYTE bootblock, bootblock_end;
|
||||
@ -81,7 +82,7 @@ char * set_dev_name(struct DeviceBase *dev) {
|
||||
if (devName == NULL) return NULL;
|
||||
strcpy(devName + 4,device_name);
|
||||
}
|
||||
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
*(ULONG *)devName = device_prefix[0];
|
||||
@ -111,33 +112,33 @@ char * set_dev_name(struct DeviceBase *dev) {
|
||||
* CreateFakeConfigDev
|
||||
* Create fake ConfigDev and DiagArea to support autoboot without requiring real autoconfig device.
|
||||
* Adapted from mounter.c by Toni Wilen
|
||||
*
|
||||
*
|
||||
* @param SysBase Pointer to SysBase
|
||||
* @param ExpansionBase Pointer to ExpansionBase
|
||||
* @returns Pointer to a ConfigDev struct
|
||||
*/
|
||||
struct ConfigDev *CreateFakeConfigDev(struct ExecBase *SysBase, struct Library *ExpansionBase)
|
||||
{
|
||||
struct ConfigDev *cd;
|
||||
struct ConfigDev *cd;
|
||||
|
||||
cd = AllocConfigDev();
|
||||
if (cd) {
|
||||
cd->cd_BoardAddr = NULL;
|
||||
cd->cd_BoardSize = 0;
|
||||
cd->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;
|
||||
cd = AllocConfigDev();
|
||||
if (cd) {
|
||||
cd->cd_BoardAddr = NULL;
|
||||
cd->cd_BoardSize = 0;
|
||||
cd->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(&bootblock, diagArea+1, bbSize);
|
||||
// cd_Rom.er_Reserved0c is used as a pointer to diagArea by strap
|
||||
ULONG *da_Pointer = (ULONG *)&cd->cd_Rom.er_Reserved0c;
|
||||
*da_Pointer = (ULONG)diagArea;
|
||||
}
|
||||
} else {
|
||||
// cd_Rom.er_Reserved0c is used as a pointer to diagArea by strap
|
||||
ULONG *da_Pointer = (ULONG *)&cd->cd_Rom.er_Reserved0c;
|
||||
*da_Pointer = (ULONG)diagArea;
|
||||
}
|
||||
} else {
|
||||
FreeConfigDev(cd);
|
||||
cd = NULL;
|
||||
}
|
||||
@ -235,22 +236,6 @@ static void Cleanup(struct DeviceBase *dev) {
|
||||
Info("Cleaning up...\n");
|
||||
struct ExecBase *SysBase = *(struct ExecBase **)4UL;
|
||||
char *devName = dev->lib.lib_Node.ln_Name;
|
||||
struct IDEUnit *unit;
|
||||
|
||||
if (SysBase->LibNode.lib_Version >= 36) {
|
||||
ObtainSemaphoreShared(&dev->ulSem);
|
||||
} else {
|
||||
ObtainSemaphore(&dev->ulSem);
|
||||
}
|
||||
|
||||
for (unit = (struct IDEUnit *)dev->units.mlh_Head;
|
||||
unit->mn_Node.mln_Succ != NULL;
|
||||
unit = (struct IDEUnit *)unit->mn_Node.mln_Succ)
|
||||
{
|
||||
unit->cd->cd_Flags |= CDF_CONFIGME;
|
||||
}
|
||||
|
||||
ReleaseSemaphore(&dev->ulSem);
|
||||
|
||||
if (dev->ExpansionBase) CloseLibrary((struct Library *)dev->ExpansionBase);
|
||||
|
||||
@ -260,11 +245,12 @@ static void Cleanup(struct DeviceBase *dev) {
|
||||
itask->mn_Node.mln_Succ != NULL;
|
||||
itask = (struct IDETask *)itask->mn_Node.mln_Succ)
|
||||
{
|
||||
itask->cd->cd_Flags |= CDF_CONFIGME;
|
||||
FreeMem(itask,sizeof(struct IDETask));
|
||||
}
|
||||
|
||||
// if devName doesn't point to the const device_name then we need to free up that memory
|
||||
if (devName != device_name) {
|
||||
if (devName != device_name) {
|
||||
FreeMem(devName,sizeof(device_name)+4);
|
||||
devName = NULL;
|
||||
}
|
||||
@ -338,7 +324,7 @@ static BYTE detectChannels(struct ConfigDev *cd) {
|
||||
*
|
||||
* Scan for drives and initialize the driver if any are found
|
||||
*/
|
||||
struct Library __attribute__((used, saveds)) * init_device(struct ExecBase *SysBase asm("a6"), BPTR seg_list asm("a0"), struct DeviceBase *dev asm("d0"))
|
||||
struct Library * init_device(struct ExecBase *SysBase asm("a6"), BPTR seg_list asm("a0"), struct DeviceBase *dev asm("d0"))
|
||||
{
|
||||
dev->SysBase = SysBase;
|
||||
Trace("Init dev, base: %08lx\n",dev);
|
||||
@ -485,16 +471,16 @@ struct Library __attribute__((used, saveds)) * init_device(struct ExecBase *SysB
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* device dependent expunge function
|
||||
* !!! CAUTION: This function runs in a forbidden state !!!
|
||||
* This call is guaranteed to be single-threaded; only one task
|
||||
* will execute your Expunge at a time.
|
||||
*
|
||||
*
|
||||
* IMPORTANT: because Expunge is called from the memory allocator,
|
||||
* it may NEVER Wait() or otherwise take long time to complete.
|
||||
*/
|
||||
static BPTR __attribute__((used, saveds)) expunge(struct DeviceBase *dev asm("a6"))
|
||||
static BPTR expunge(struct DeviceBase *dev asm("a6"))
|
||||
{
|
||||
Trace((CONST_STRPTR) "running expunge()\n");
|
||||
|
||||
@ -509,13 +495,13 @@ static BPTR __attribute__((used, saveds)) expunge(struct DeviceBase *dev asm("a6
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* device dependent open function
|
||||
* !!! CAUTION: This function runs in a forbidden state !!!
|
||||
* This call is guaranteed to be single-threaded; only one task
|
||||
* will execute your Open at a time.
|
||||
* will execute your Open at a time.
|
||||
*/
|
||||
static void __attribute__((used, saveds)) open(struct DeviceBase *dev asm("a6"), struct IORequest *ioreq asm("a1"), ULONG unitnum asm("d0"), ULONG flags asm("d1"))
|
||||
static void open(struct DeviceBase *dev asm("a6"), struct IORequest *ioreq asm("a1"), ULONG unitnum asm("d0"), ULONG flags asm("d1"))
|
||||
{
|
||||
struct ExecBase *SysBase = dev->SysBase;
|
||||
struct IDEUnit *unit = NULL;
|
||||
@ -563,7 +549,7 @@ static void __attribute__((used, saveds)) open(struct DeviceBase *dev asm("a6"),
|
||||
|
||||
ReleaseSemaphore(&dev->ulSem);
|
||||
|
||||
if (found == false || unit->present == false) {
|
||||
if (found == false || unit->flags.present == false) {
|
||||
error = TDERR_BadUnitNum;
|
||||
goto exit;
|
||||
}
|
||||
@ -622,19 +608,19 @@ static void td_get_geometry(struct IOStdReq *ioreq) {
|
||||
geometry->dg_TrackSectors = unit->sectorsPerTrack;
|
||||
geometry->dg_BufMemType = MEMF_PUBLIC;
|
||||
geometry->dg_DeviceType = unit->deviceType;
|
||||
geometry->dg_Flags = (unit->atapi) ? DGF_REMOVABLE : 0;
|
||||
geometry->dg_Flags = (unit->flags.atapi) ? DGF_REMOVABLE : 0;
|
||||
|
||||
ioreq->io_Actual = sizeof(struct DriveGeometry);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* device dependent close function
|
||||
* !!! CAUTION: This function runs in a forbidden state !!!
|
||||
* This call is guaranteed to be single-threaded; only one task
|
||||
* will execute your Close at a time.
|
||||
* will execute your Close at a time.
|
||||
*/
|
||||
static BPTR __attribute__((used, saveds)) close(struct DeviceBase *dev asm("a6"), struct IORequest *ioreq asm("a1"))
|
||||
static BPTR close(struct DeviceBase *dev asm("a6"), struct IORequest *ioreq asm("a1"))
|
||||
{
|
||||
if (ioreq_is_valid(dev,ioreq)) {
|
||||
struct IDEUnit *unit = (struct IDEUnit *)ioreq->io_Unit;
|
||||
@ -695,7 +681,7 @@ const UWORD supported_commands[] =
|
||||
*
|
||||
* Handle immediate requests and send any others to ide_task
|
||||
*/
|
||||
static void __attribute__((used, saveds)) begin_io(struct DeviceBase *dev asm("a6"), struct IOStdReq *ioreq asm("a1"))
|
||||
static void begin_io(struct DeviceBase *dev asm("a6"), struct IOStdReq *ioreq asm("a1"))
|
||||
{
|
||||
struct ExecBase *SysBase = dev->SysBase;
|
||||
|
||||
@ -805,7 +791,7 @@ static void __attribute__((used, saveds)) begin_io(struct DeviceBase *dev asm("a
|
||||
case CMD_START:
|
||||
case CMD_STOP:
|
||||
// Don't pass it to the task if it's not an atapi device
|
||||
if (!unit->atapi) {
|
||||
if (!unit->flags.atapi) {
|
||||
error = 0;
|
||||
break;
|
||||
}
|
||||
@ -878,7 +864,7 @@ sendToTask:
|
||||
*
|
||||
* Abort io request
|
||||
*/
|
||||
static ULONG __attribute__((used, saveds)) abort_io(struct DeviceBase *dev asm("a6"), struct IOStdReq *ioreq asm("a1"))
|
||||
static ULONG abort_io(struct DeviceBase *dev asm("a6"), struct IOStdReq *ioreq asm("a1"))
|
||||
{
|
||||
struct ExecBase *SysBase = dev->SysBase;
|
||||
|
||||
@ -925,69 +911,117 @@ static const ULONG device_vectors[] =
|
||||
-1 //function table end marker
|
||||
};
|
||||
|
||||
/**
|
||||
* AdjustBootPriority
|
||||
*
|
||||
* Adjusts the boot priority of the first matching device in a mount list. Searches
|
||||
* for a device node with the specified name and increases its priority by the given
|
||||
* increment. Optionally checks gameport 1 button state before applying changes.
|
||||
* Re-orders the device in the priority list after modification.
|
||||
*
|
||||
* @param bootname BSTR name to match against device nodes
|
||||
* @param MountList Pointer to the mount list to traverse
|
||||
* @param checkFire If true, only modify when gameport 1 button is pressed
|
||||
* @param increment Amount to increase both device and boot node priorities
|
||||
*/
|
||||
void AdjustBootPriority(struct ExecBase *SysBase, char *bootname, struct List *MountList, bool checkFire, int increment) {
|
||||
volatile struct CIA *ciaa = (struct CIA *)0x0bfe001;
|
||||
struct BootNode *bn;
|
||||
struct DeviceNode *dn;
|
||||
|
||||
for (bn = (struct BootNode *)MountList->lh_Head;
|
||||
bn->bn_Node.ln_Succ;
|
||||
bn = (struct BootNode *)bn->bn_Node.ln_Succ)
|
||||
{
|
||||
dn = bn->bn_DeviceNode;
|
||||
if (dn->dn_Priority != -128)
|
||||
{
|
||||
if (L_CompareBSTR(BADDR(dn->dn_Name),bootname)) {
|
||||
if(!checkFire || (ciaa->ciapra & CIAF_GAMEPORT1)==0) {
|
||||
dn->dn_Priority+=increment;
|
||||
bn->bn_Node.ln_Pri+=increment;
|
||||
Remove((struct Node *)bn);
|
||||
Enqueue(MountList,(struct Node *)bn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TweakBootList
|
||||
*
|
||||
* Modifies boot device priorities in the expansion library mount list. Traverses all
|
||||
* boot nodes and increases priority (+1) for devices matching "BOOTxx" names (where xx
|
||||
* is the expansion library major version). Additionally boosts priority (+2) for
|
||||
* "BOOT00" devices when gameport 1 button is pressed. Skips devices with priority -128.
|
||||
*
|
||||
* @param SysBase Pointer to the ExecBase system library base
|
||||
*/
|
||||
void TweakBootList(struct ExecBase *SysBase) {
|
||||
struct ExpansionBase *ExpansionBase;
|
||||
|
||||
if (ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library",0)) {
|
||||
char bootname[] = "\6BOOT00"; // BSTR
|
||||
|
||||
UWORD major = (ExpansionBase->LibNode.lib_Version)%100; // we assume version number is under 100, but better safe than sorry
|
||||
|
||||
Forbid();
|
||||
|
||||
AdjustBootPriority(SysBase,bootname,&ExpansionBase->MountList,true,2);
|
||||
|
||||
bootname[5]=0x30+(major/10);
|
||||
bootname[6]=0x30+(major%10);
|
||||
|
||||
AdjustBootPriority(SysBase,bootname,&ExpansionBase->MountList,false,1);
|
||||
|
||||
Permit();
|
||||
|
||||
CloseLibrary((struct Library *)ExpansionBase);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* init
|
||||
*
|
||||
* Create the device and add it to the system if init_device succeeds
|
||||
*/
|
||||
static struct Library __attribute__((used)) * init(BPTR seg_list asm("a0"))
|
||||
static struct Library * init(BPTR seg_list asm("a0"))
|
||||
{
|
||||
struct ExecBase *SysBase = *(struct ExecBase **)4UL;
|
||||
Info("Init driver.\n");
|
||||
struct MountStruct *ms = NULL;
|
||||
struct DeviceBase *mydev = (struct DeviceBase *)MakeLibrary((ULONG *)&device_vectors, // Vectors
|
||||
NULL, // InitStruct data
|
||||
(APTR)init_device, // Init function
|
||||
sizeof(struct DeviceBase), // Library data size
|
||||
seg_list); // Segment list
|
||||
|
||||
BOOL CDBoot = FindCDFS();
|
||||
|
||||
if (mydev != NULL) {
|
||||
ULONG ms_size = (sizeof(struct MountStruct) + (MAX_UNITS * sizeof(struct UnitStruct)));
|
||||
Info("Add Device.\n");
|
||||
AddDevice((struct Device *)mydev);
|
||||
|
||||
if ((ms = AllocMem(ms_size,MEMF_ANY|MEMF_PUBLIC)) == NULL) goto done;
|
||||
struct IDETask *itask = (struct IDETask *)mydev->ideTasks.mlh_Head;
|
||||
|
||||
ms->deviceName = mydev->lib.lib_Node.ln_Name;
|
||||
ms->creatorName = NULL;
|
||||
ms->numUnits = 0;
|
||||
ms->SysBase = SysBase;
|
||||
if (!itask->mn_Node.mln_Succ) goto done;
|
||||
|
||||
UWORD index = 0;
|
||||
#if CDBOOT
|
||||
BOOL CDBoot = FindCDFS();
|
||||
#endif
|
||||
struct IDEUnit *unit;
|
||||
struct MountStruct ms = {
|
||||
.deviceName = mydev->lib.lib_Node.ln_Name,
|
||||
.creatorName = mydev->lib.lib_Node.ln_Name,
|
||||
.SysBase = SysBase,
|
||||
.cdBoot = CDBoot,
|
||||
.luns = false,
|
||||
.slowSpinup = false,
|
||||
.ignoreLast = true,
|
||||
.configDev = itask->cd
|
||||
};
|
||||
|
||||
if (SysBase->LibNode.lib_Version >= 36) {
|
||||
ObtainSemaphoreShared(&mydev->ulSem);
|
||||
} else {
|
||||
ObtainSemaphore(&mydev->ulSem);
|
||||
}
|
||||
MountDrive(&ms);
|
||||
|
||||
for (unit = (struct IDEUnit *)mydev->units.mlh_Head;
|
||||
unit->mn_Node.mln_Succ != NULL;
|
||||
unit = (struct IDEUnit *)unit->mn_Node.mln_Succ)
|
||||
{
|
||||
if (unit->present == true) {
|
||||
#if CDBOOT
|
||||
// If CDFS not resident don't bother adding the CDROM to the mountlist
|
||||
if (unit->deviceType == DG_CDROM && !CDBoot) continue;
|
||||
#endif
|
||||
ms->Units[index].unitNum = unit->unitNum;
|
||||
ms->Units[index].configDev = unit->cd;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
ms->numUnits = index;
|
||||
|
||||
ReleaseSemaphore(&mydev->ulSem);
|
||||
if (ms->numUnits > 0) {
|
||||
MountDrive(ms);
|
||||
}
|
||||
|
||||
FreeMem(ms,ms_size);
|
||||
if (!seg_list) // Only tweak if we're in boot
|
||||
TweakBootList(SysBase);
|
||||
}
|
||||
done:
|
||||
return (struct Library *)mydev;
|
||||
|
||||
21
device.h
21
device.h
@ -44,8 +44,6 @@ struct Drive {
|
||||
|
||||
struct IDEUnit {
|
||||
struct MinNode mn_Node;
|
||||
struct Unit io_unit;
|
||||
struct ConfigDev *cd;
|
||||
struct ExecBase *SysBase;
|
||||
struct IDETask *itask;
|
||||
struct Drive drive;
|
||||
@ -58,17 +56,8 @@ struct IDEUnit {
|
||||
volatile UBYTE *shadowDevHead;
|
||||
volatile void *changeInt;
|
||||
UBYTE unitNum;
|
||||
UBYTE channel;
|
||||
UBYTE deviceType;
|
||||
UBYTE last_error[6];
|
||||
bool primary;
|
||||
bool present;
|
||||
bool atapi;
|
||||
bool mediumPresent;
|
||||
bool mediumPresentPrev;
|
||||
bool xferMultiple;
|
||||
bool lba;
|
||||
bool lba48;
|
||||
UWORD openCount;
|
||||
UWORD changeCount;
|
||||
UWORD heads;
|
||||
@ -79,6 +68,16 @@ struct IDEUnit {
|
||||
ULONG logicalSectors;
|
||||
struct MinList changeInts;
|
||||
UBYTE multipleCount;
|
||||
struct {
|
||||
unsigned char primary : 1;
|
||||
unsigned char present : 1;
|
||||
unsigned char atapi : 1;
|
||||
unsigned char mediumPresent : 1;
|
||||
unsigned char mediumPresentPrev : 1;
|
||||
unsigned char xferMultiple : 1;
|
||||
unsigned char lba : 1;
|
||||
unsigned char lba48 : 1;
|
||||
} flags;
|
||||
};
|
||||
|
||||
struct DeviceBase {
|
||||
|
||||
74
idetask.c
74
idetask.c
@ -165,7 +165,7 @@ static BYTE scsi_read_capacity_ata(struct IDEUnit *unit, struct SCSICmd *scsi_co
|
||||
if (cdb->flags & 0x01) {
|
||||
// Partial Medium Indicator - Return end of cylinder
|
||||
// Implement this so HDToolbox stops moaning about track size
|
||||
ULONG spc = unit->cylinders * unit->heads;
|
||||
ULONG spc = unit->sectorsPerTrack * unit->heads;
|
||||
data->lba = (((cdb->lba / spc) + 1) * spc) - 1;
|
||||
} else {
|
||||
data->lba = (unit->logicalSectors) - 1;
|
||||
@ -213,7 +213,7 @@ static BYTE scsi_mode_sense_ata(struct IDEUnit *unit, struct SCSICmd *scsi_comma
|
||||
UBYTE idx = 4;
|
||||
if (page == 0x3F || page == 0x03) {
|
||||
data[idx++] = 0x03; // Page Code: Format Parameters
|
||||
data[idx++] = 0x18; // Page length
|
||||
data[idx++] = 0x16; // Page length
|
||||
for (int i=0; i <8; i++) {
|
||||
data[idx++] = 0;
|
||||
}
|
||||
@ -221,19 +221,19 @@ static BYTE scsi_mode_sense_ata(struct IDEUnit *unit, struct SCSICmd *scsi_comma
|
||||
data[idx++] = unit->sectorsPerTrack;
|
||||
data[idx++] = (unit->blockSize >> 8);
|
||||
data[idx++] = unit->blockSize;
|
||||
for (int i=0; i<12; i++) {
|
||||
for (int i=0; i<10; i++) {
|
||||
data[idx++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (page == 0x3F || page == 0x04) {
|
||||
data[idx++] = 0x04; // Page code: Rigid Drive Geometry Parameters
|
||||
data[idx++] = 0x17; // Page length
|
||||
data[idx++] = 0x16; // Page length
|
||||
data[idx++] = (unit->cylinders >> 16);
|
||||
data[idx++] = (unit->cylinders >> 8);
|
||||
data[idx++] = unit->cylinders;
|
||||
data[idx++] = unit->heads;
|
||||
for (int i=0; i<19; i++) {
|
||||
for (int i=0; i<18; i++) {
|
||||
data[idx++] = 0;
|
||||
}
|
||||
}
|
||||
@ -267,7 +267,7 @@ static BYTE handle_scsi_command(struct IOStdReq *ioreq) {
|
||||
|
||||
Trace("SCSI: Command %lx\n",*scsi_command->scsi_Command);
|
||||
|
||||
if (unit->atapi == false)
|
||||
if (unit->flags.atapi == false)
|
||||
{
|
||||
// Non-ATAPI drives - Translate SCSI CMD to ATA
|
||||
switch (scsi_command->scsi_Command[0]) {
|
||||
@ -422,25 +422,24 @@ static BYTE init_units(struct IDETask *itask) {
|
||||
|
||||
for (BYTE i=0; i < 2; i++) {
|
||||
struct IDEUnit *unit = AllocMem(sizeof(struct IDEUnit),MEMF_ANY|MEMF_CLEAR);
|
||||
|
||||
if (unit != NULL) {
|
||||
// Setup each unit structure
|
||||
unit->itask = itask;
|
||||
unit->unitNum = ((itask->boardNum * 4) + (itask->channel << 1) + i);
|
||||
unit->SysBase = SysBase;
|
||||
unit->cd = itask->cd;
|
||||
unit->primary = ((i%2) == 1) ? false : true;
|
||||
unit->channel = itask->channel;
|
||||
unit->openCount = 0;
|
||||
unit->changeCount = 1;
|
||||
unit->deviceType = DG_DIRECT_ACCESS;
|
||||
unit->mediumPresent = false;
|
||||
unit->mediumPresentPrev = false;
|
||||
unit->present = false;
|
||||
unit->atapi = false;
|
||||
unit->xferMultiple = false;
|
||||
unit->multipleCount = 0;
|
||||
unit->shadowDevHead = &itask->shadowDevHead;
|
||||
*unit->shadowDevHead = 0;
|
||||
unit->itask = itask;
|
||||
unit->unitNum = ((itask->boardNum * 4) + (itask->channel << 1) + i);
|
||||
unit->SysBase = SysBase;
|
||||
unit->flags.primary = ((i%2) == 1) ? false : true;
|
||||
unit->openCount = 0;
|
||||
unit->changeCount = 1;
|
||||
unit->deviceType = DG_DIRECT_ACCESS;
|
||||
unit->flags.mediumPresent = false;
|
||||
unit->flags.mediumPresentPrev = false;
|
||||
unit->flags.present = false;
|
||||
unit->flags.atapi = false;
|
||||
unit->flags.xferMultiple = false;
|
||||
unit->multipleCount = 0;
|
||||
unit->shadowDevHead = &itask->shadowDevHead;
|
||||
*unit->shadowDevHead = 0;
|
||||
|
||||
// Initialize the change int list
|
||||
unit->changeInts.mlh_Tail = NULL;
|
||||
@ -449,8 +448,11 @@ static BYTE init_units(struct IDETask *itask) {
|
||||
|
||||
Warn("testing unit %ld\n",unit->unitNum);
|
||||
|
||||
if (ata_init_unit(unit)) {
|
||||
if (unit->atapi) itask->hasRemovables = true;
|
||||
void *base = itask->cd->cd_BoardAddr;
|
||||
base += (itask->channel == 0) ? CHANNEL_0 : CHANNEL_1;
|
||||
|
||||
if (ata_init_unit(unit,base)) {
|
||||
if (unit->flags.atapi) itask->hasRemovables = true;
|
||||
num_units++;
|
||||
itask->dev->numUnits++;
|
||||
dev->highestUnit = unit->unitNum;
|
||||
@ -524,11 +526,11 @@ static void diskchange_check(struct IDETask *itask) {
|
||||
unit->mn_Node.mln_Succ != NULL;
|
||||
unit = (struct IDEUnit *)unit->mn_Node.mln_Succ)
|
||||
{
|
||||
if (unit->present && unit->atapi) {
|
||||
if (unit->flags.present && unit->flags.atapi) {
|
||||
|
||||
present = (atapi_test_unit_ready(unit,true) == 0) ? true : false;
|
||||
|
||||
if (present != unit->mediumPresentPrev) {
|
||||
if (present != unit->flags.mediumPresentPrev) {
|
||||
|
||||
Forbid();
|
||||
if (unit->changeInt != NULL)
|
||||
@ -545,7 +547,7 @@ static void diskchange_check(struct IDETask *itask) {
|
||||
Permit();
|
||||
}
|
||||
|
||||
unit->mediumPresentPrev = present;
|
||||
unit->flags.mediumPresentPrev = present;
|
||||
|
||||
|
||||
}
|
||||
@ -585,23 +587,23 @@ static void process_ioreq(struct IDETask *itask, struct IOStdReq *ioreq) {
|
||||
return;
|
||||
|
||||
case CMD_START:
|
||||
if (unit->atapi) {
|
||||
if (unit->flags.atapi) {
|
||||
error = atapi_start_stop_unit(unit,true,false,false);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_STOP:
|
||||
if (unit->atapi) {
|
||||
if (unit->flags.atapi) {
|
||||
error = atapi_start_stop_unit(unit,false,false,false);
|
||||
}
|
||||
break;
|
||||
|
||||
case TD_EJECT:
|
||||
if (!unit->atapi) {
|
||||
if (!unit->flags.atapi) {
|
||||
error = IOERR_NOCMD;
|
||||
break;
|
||||
}
|
||||
ioreq->io_Actual = (unit->mediumPresent) ? 0 : 1; // io_Actual reflects the previous state
|
||||
ioreq->io_Actual = (unit->flags.mediumPresent) ? 0 : 1; // io_Actual reflects the previous state
|
||||
|
||||
bool insert = (ioreq->io_Length == 0) ? true : false;
|
||||
|
||||
@ -611,7 +613,7 @@ static void process_ioreq(struct IDETask *itask, struct IOStdReq *ioreq) {
|
||||
case TD_CHANGESTATE:
|
||||
error = 0;
|
||||
ioreq->io_Actual = 0;
|
||||
if (unit->atapi) {
|
||||
if (unit->flags.atapi) {
|
||||
ioreq->io_Actual = (atapi_test_unit_ready(unit,false) != 0);
|
||||
break;
|
||||
}
|
||||
@ -619,7 +621,7 @@ static void process_ioreq(struct IDETask *itask, struct IOStdReq *ioreq) {
|
||||
|
||||
case TD_PROTSTATUS:
|
||||
error = 0;
|
||||
if (unit->atapi) {
|
||||
if (unit->flags.atapi) {
|
||||
if ((error = atapi_check_wp(unit)) == TDERR_WriteProt) {
|
||||
error = 0;
|
||||
ioreq->io_Actual = 1;
|
||||
@ -660,7 +662,7 @@ validate_etd:
|
||||
case NSCMD_TD_FORMAT64:
|
||||
direction = WRITE;
|
||||
transfer:
|
||||
if (unit->atapi == true && unit->mediumPresent == false) {
|
||||
if (unit->flags.atapi == true && unit->flags.mediumPresent == false) {
|
||||
Trace("Access attempt without media\n");
|
||||
error = TDERR_DiskChanged;
|
||||
break;
|
||||
@ -681,7 +683,7 @@ transfer:
|
||||
break;
|
||||
}
|
||||
|
||||
if (unit->atapi == true) {
|
||||
if (unit->flags.atapi == true) {
|
||||
error = atapi_translate(ioreq->io_Data, lba, count, &ioreq->io_Actual, unit, direction);
|
||||
} else {
|
||||
if (direction == READ) {
|
||||
|
||||
72
lide_alib.c
72
lide_alib.c
@ -7,6 +7,7 @@
|
||||
#include <exec/nodes.h>
|
||||
#include <exec/ports.h>
|
||||
#include <proto/exec.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "debug.h"
|
||||
|
||||
@ -18,9 +19,9 @@
|
||||
|
||||
/**
|
||||
* L_NewList
|
||||
*
|
||||
*
|
||||
* Initialize a new list
|
||||
*
|
||||
*
|
||||
* @param new_list Pointer to a new list
|
||||
*/
|
||||
void L_NewList(struct List *new_list) {
|
||||
@ -31,9 +32,9 @@ void L_NewList(struct List *new_list) {
|
||||
|
||||
/**
|
||||
* L_CreatePort
|
||||
*
|
||||
*
|
||||
* Create a new MsgPort
|
||||
*
|
||||
*
|
||||
* @param name (optional) name of the port
|
||||
* @param priority priority of the port
|
||||
* @returns pointer to a MsgPort
|
||||
@ -49,7 +50,7 @@ struct MsgPort *L_CreatePort(STRPTR name, LONG pri) {
|
||||
mp->mp_Node.ln_Name = name;
|
||||
mp->mp_SigBit = sigNum;
|
||||
mp->mp_SigTask = FindTask(0);
|
||||
|
||||
|
||||
L_NewList(&mp->mp_MsgList);
|
||||
|
||||
if (mp->mp_Node.ln_Name)
|
||||
@ -62,9 +63,9 @@ struct MsgPort *L_CreatePort(STRPTR name, LONG pri) {
|
||||
|
||||
/**
|
||||
* L_DeletePort
|
||||
*
|
||||
*
|
||||
* Delete a MsgPort
|
||||
*
|
||||
*
|
||||
* @param mp Pointer to a MsgPort
|
||||
*/
|
||||
void L_DeletePort(struct MsgPort *mp) {
|
||||
@ -73,7 +74,7 @@ void L_DeletePort(struct MsgPort *mp) {
|
||||
if (mp) {
|
||||
if (mp->mp_Node.ln_Name)
|
||||
RemPort(mp);
|
||||
|
||||
|
||||
FreeSignal(mp->mp_SigBit);
|
||||
FreeMem(mp,sizeof(struct MsgPort));
|
||||
}
|
||||
@ -81,9 +82,9 @@ void L_DeletePort(struct MsgPort *mp) {
|
||||
|
||||
/**
|
||||
* L_CreateExtIO
|
||||
*
|
||||
*
|
||||
* Create an Extended IO Request
|
||||
*
|
||||
*
|
||||
* @param mp Pointer to the reply port
|
||||
* @param size Size of the IO request
|
||||
* @return pointer to the IO request
|
||||
@ -105,9 +106,9 @@ struct IORequest* L_CreateExtIO(struct MsgPort *mp, ULONG size) {
|
||||
|
||||
/**
|
||||
* L_CreateStdIO
|
||||
*
|
||||
*
|
||||
* Create a standard IO Request
|
||||
*
|
||||
*
|
||||
* @param mp Pointer to the reply port
|
||||
* @return Pointer to an IOStdReq
|
||||
*/
|
||||
@ -117,9 +118,9 @@ struct IOStdReq* L_CreateStdIO(struct MsgPort *mp) {
|
||||
|
||||
/**
|
||||
* L_DeleteExtIO
|
||||
*
|
||||
*
|
||||
* Delete an Extended IO Request
|
||||
*
|
||||
*
|
||||
* @param ior Pointer to an IORequest
|
||||
*/
|
||||
void L_DeleteExtIO(struct IORequest *ior) {
|
||||
@ -133,9 +134,9 @@ void L_DeleteExtIO(struct IORequest *ior) {
|
||||
|
||||
/**
|
||||
* L_DeleteStdIO
|
||||
*
|
||||
*
|
||||
* Delete a Standard IO Requesrt
|
||||
*
|
||||
*
|
||||
* @param ior Pointer to an IOStdReq
|
||||
*/
|
||||
void L_DeleteStdIO(struct IOStdReq *ior) {
|
||||
@ -192,4 +193,43 @@ struct Task *L_CreateTask(char * taskName, LONG priority, APTR funcEntry, ULONG
|
||||
AddTask(task,funcEntry,NULL);
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
/**
|
||||
* L_Uppercase
|
||||
* Convert lowercase char to uppercase
|
||||
*
|
||||
* @param c char to uppercase
|
||||
* @returns char
|
||||
*/
|
||||
|
||||
char L_UpperCase(char c) {
|
||||
if (c >= 'a' && c <= 'z')
|
||||
c -= ('a'-'A');
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* L_CompareBSTR
|
||||
* Compare two BSTRs
|
||||
*
|
||||
* @param str1 String 1
|
||||
* @param str2 String 2
|
||||
* @returns bool Equality
|
||||
*/
|
||||
bool L_CompareBSTR(char *str1, char *str2) {
|
||||
UBYTE len1 = str1[0];
|
||||
UBYTE len2 = str2[0];
|
||||
|
||||
if (len1 != len2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i=1; i<=len1; i++) {
|
||||
if (L_UpperCase(str1[i]) != L_UpperCase(str2[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -19,4 +19,6 @@ struct IOStdReq* L_CreateStdIO(struct MsgPort *mp);
|
||||
void L_DeleteExtIO(struct IORequest *ior);
|
||||
void L_DeleteStdIO(struct IOStdReq *ior);
|
||||
struct Task *L_CreateTask(char * taskName, LONG priority, APTR funcEntry, ULONG stackSize, APTR userData);
|
||||
bool L_CompareBSTR(char *str1, char *str2);
|
||||
char L_UpperCase(char c);
|
||||
#endif
|
||||
123
lideflash/main.c
123
lideflash/main.c
@ -304,15 +304,20 @@ static void setup_liv2_board(struct ideBoard *board) {
|
||||
/**
|
||||
* promptUser
|
||||
*
|
||||
* Ask if the user wants to update this board
|
||||
* Ask if the user wants to update/erase this board
|
||||
* @param config pointer to the config struct
|
||||
* @return boolean true / false
|
||||
*/
|
||||
static bool promptUser(struct Config *config) {
|
||||
static bool promptUser(struct Config *config, bool update) {
|
||||
int c;
|
||||
char answer = 'y'; // Default to yes
|
||||
|
||||
printf("Update this device? (Y)es/(n)o/(a)ll: ");
|
||||
if (update) {
|
||||
printf("Update this device?");
|
||||
} else {
|
||||
printf("Erase flash?");
|
||||
}
|
||||
printf(" (Y)es/(n)o/(a)ll: ");
|
||||
|
||||
if (config->assumeYes) {
|
||||
printf("y\n");
|
||||
@ -334,7 +339,7 @@ static bool promptUser(struct Config *config) {
|
||||
/**
|
||||
* assemble_rom
|
||||
*
|
||||
* Given either lide.rom or lide-atbus.rom - adjust the file for the currebt board
|
||||
* Given either lide.rom or lide-atbus.rom - adjust the file for the current board
|
||||
* This is needed because lideflash will update all compatible boards, and can only be supplied with one filename
|
||||
*/
|
||||
static void assemble_rom(char *src_buffer, char *dst_buffer, ULONG bufSize, enum BOOTROM dstRomType) {
|
||||
@ -367,6 +372,90 @@ static void assemble_rom(char *src_buffer, char *dst_buffer, ULONG bufSize, enum
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* find_lide_version
|
||||
*
|
||||
* Search for the id string in the buffer and return the offset if found
|
||||
* @param buffer the buffer to search
|
||||
* @param romSize Size of the ROM
|
||||
* @returns offset. negative if not found
|
||||
*/
|
||||
static int find_lide_version(const unsigned char *buffer, ULONG romSize) {
|
||||
const char *needle = "lide ";
|
||||
size_t needle_len = strlen(needle);
|
||||
|
||||
// We can only search up to (romSize - needle_len)
|
||||
for (size_t i = 0; i <= romSize - needle_len; i++) {
|
||||
if (memcmp(buffer + i, needle, needle_len) == 0) {
|
||||
return (int)i;
|
||||
}
|
||||
}
|
||||
return -1; // Not found
|
||||
}
|
||||
|
||||
/**
|
||||
* printVersion
|
||||
*
|
||||
* Print the version string without the git information
|
||||
*
|
||||
* @param version Pointer to the version string
|
||||
*/
|
||||
static void printVersion(char *version) {
|
||||
char *temp;
|
||||
int len = strcspn(version,")");
|
||||
len++; // Leave space for null terminator
|
||||
if ((temp = AllocMem(len,MEMF_ANY))) {
|
||||
temp[len] = 0;
|
||||
strncpy(temp,version,len);
|
||||
printf("%s\n",temp);
|
||||
FreeMem(temp,len);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* printCurrentVersion
|
||||
*
|
||||
* Print the current version of lide the board is running
|
||||
* It first tries to get this using the cd_Driver pointer in the struct
|
||||
*
|
||||
* Older driver versions didn't set this, in that case:
|
||||
* 1. Traverse the eb_Mountlist looking for a device bound to this configDev
|
||||
* 2. Peek into it's BootNode->DeviceNode->FSSM to get the device name
|
||||
* 3. Find the device in SysBase->DeviceList
|
||||
*
|
||||
* @param cd ConfigDev pointer
|
||||
*/
|
||||
void printCurrentVersion(struct ConfigDev *cd) {
|
||||
struct BootNode *bn;
|
||||
struct DeviceNode *dn;
|
||||
struct FileSysStartupMsg *fssm;
|
||||
struct Device *device;
|
||||
char *deviceName = NULL;
|
||||
|
||||
if ((device = cd->cd_Driver) == NULL) {
|
||||
// Old version of lide didn't set cd_Driver
|
||||
// Get it the hard way
|
||||
for (bn = (struct BootNode *)ExpansionBase->MountList.lh_Head;
|
||||
bn->bn_Node.ln_Succ;
|
||||
bn = (struct BootNode *)bn->bn_Node.ln_Succ)
|
||||
{
|
||||
if (cd == (struct ConfigDev *)bn->bn_Node.ln_Name) {
|
||||
dn = bn->bn_DeviceNode;
|
||||
fssm = BADDR(dn->dn_Startup);
|
||||
deviceName = (char *)BADDR(fssm->fssm_Device) + 1; // NULL terminated BSTR
|
||||
device = (struct Device *)FindName(&SysBase->DeviceList,deviceName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (device) {
|
||||
printVersion(device->dd_Library.lib_IdString);
|
||||
} else {
|
||||
printf("Unknown\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
SysBase = *((struct ExecBase **)4UL);
|
||||
@ -379,6 +468,8 @@ int main(int argc, char *argv[])
|
||||
void *driver_buffer2 = NULL;
|
||||
void *misc_buffer = NULL;
|
||||
|
||||
char *ver = NULL;
|
||||
|
||||
ULONG romSize = 0;
|
||||
ULONG miscSize = 0;
|
||||
|
||||
@ -424,6 +515,15 @@ int main(int argc, char *argv[])
|
||||
rc = 5;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
int ver_offset = find_lide_version(driver_buffer,romSize);
|
||||
if (ver_offset > 0) {
|
||||
ver = (char *)driver_buffer + ver_offset;
|
||||
if (ver) {
|
||||
printf("New version: ");
|
||||
printVersion(ver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config->misc_filename) {
|
||||
@ -463,11 +563,12 @@ int main(int argc, char *argv[])
|
||||
|
||||
devsInhibited = true;
|
||||
|
||||
printf("\n");
|
||||
|
||||
if ((ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library",0)) != NULL) {
|
||||
|
||||
struct ConfigDev *cd = NULL;
|
||||
struct ideBoard board;
|
||||
|
||||
while ((cd = FindConfigDev(cd,-1,-1)) != NULL) {
|
||||
|
||||
board.cd = cd;
|
||||
@ -575,11 +676,19 @@ int main(int argc, char *argv[])
|
||||
continue; // Skip this board
|
||||
}
|
||||
|
||||
printf(" at Address 0x%06x\n",(int)cd->cd_BoardAddr);
|
||||
printf(" at Address 0x%06X\n",(int)cd->cd_BoardAddr);
|
||||
boards_found++;
|
||||
if (config->ide_rom_filename) {
|
||||
printf("Current version: ");
|
||||
printCurrentVersion(cd);
|
||||
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
bool update = (config->ide_rom_filename != NULL|| config->misc_filename != NULL);
|
||||
|
||||
// Ask the user if they wish to update this board
|
||||
if (!promptUser(config)) continue;
|
||||
if (!promptUser(config, update)) continue;
|
||||
|
||||
suspend_lide(true);
|
||||
|
||||
|
||||
@ -161,14 +161,14 @@ static void DumpUnit(struct IOStdReq *req) {
|
||||
|
||||
printf("Device Type: %d\n", unit->deviceType);
|
||||
printf("Transfer method: %d\n", unit->xferMethod);
|
||||
printf("Primary: %s\n", (unit->primary) ? "Yes" : "No");
|
||||
printf("ATAPI: %s\n", (unit->atapi) ? "Yes" : "No");
|
||||
printf("Medium Present: %s\n", (unit->mediumPresent) ? "Yes" : "No");
|
||||
printf("Supports LBA: %s\n", (unit->lba) ? "Yes" : "No");
|
||||
printf("Supports LBA48: %s\n", (unit->lba48) ? "Yes" : "No");
|
||||
printf("Primary: %s\n", (unit->flags.primary) ? "Yes" : "No");
|
||||
printf("ATAPI: %s\n", (unit->flags.atapi) ? "Yes" : "No");
|
||||
printf("Medium Present: %s\n", (unit->flags.mediumPresent) ? "Yes" : "No");
|
||||
printf("Supports LBA: %s\n", (unit->flags.lba) ? "Yes" : "No");
|
||||
printf("Supports LBA48: %s\n", (unit->flags.lba48) ? "Yes" : "No");
|
||||
printf("C/H/S: %d/%d/%d\n", unit->cylinders, unit->heads, unit->sectorsPerTrack);
|
||||
printf("Logical Sectors: %ld\n", (long int)unit->logicalSectors);
|
||||
printf("READ/WRITE Multiple: %s\n", (unit->xferMultiple) ? "Yes" : "No");
|
||||
printf("READ/WRITE Multiple: %s\n", (unit->flags.xferMultiple) ? "Yes" : "No");
|
||||
printf("Multiple count: %d\n", unit->multipleCount);
|
||||
printf("Last Error: ");
|
||||
for (int i=0; i<6; i++) {
|
||||
@ -298,12 +298,12 @@ static void setMultiple(struct IOStdReq *req, int multiple) {
|
||||
struct IDEUnit *unit = (struct IDEUnit *)req->io_Unit;
|
||||
|
||||
if (multiple > 0) {
|
||||
unit->xferMultiple = true;
|
||||
unit->flags.xferMultiple = true;
|
||||
unit->multipleCount = multiple;
|
||||
printf("set multiple transfer: %d\n",multiple);
|
||||
} else {
|
||||
printf("Transfer multiple disabled.\n");
|
||||
unit->xferMultiple = false;
|
||||
unit->flags.xferMultiple = false;
|
||||
unit->multipleCount = 1;
|
||||
}
|
||||
|
||||
|
||||
212
mounter/README.md
Normal file
212
mounter/README.md
Normal file
@ -0,0 +1,212 @@
|
||||
# Mounter: AmigaOS Generic Mounter
|
||||
|
||||
Generic autoboot / automount RDB parser and mounter.
|
||||
|
||||
This is the mounter code from a4091.device.
|
||||
|
||||
## 1. Introduction
|
||||
|
||||
This Mounter software is a generic, autoboot/automount Rigid Disk Block (RDB)
|
||||
parser and mounter for AmigaOS. Originally developed by Toni Wilen and extended
|
||||
by Stefan Reinauer and Matt Harlum. It is used by the `a4091.device` and
|
||||
'lide.device' drivers. This software is engineered to be a robust and highly
|
||||
compatible solution for device drivers that need to mount partitions and
|
||||
filesystems at boot time.
|
||||
|
||||
It is designed to be highly portable, 68000-compatible, and capable of
|
||||
operating in diverse environments, from a Kickstart 1.3 Boot ROM to a modern
|
||||
AmigaOS system. Its primary function is to scan for storage devices, interpret
|
||||
their partition maps (RDB, MBR, GPT), load the necessary filesystems, and make
|
||||
them available to the operating system.
|
||||
|
||||
---
|
||||
|
||||
## 2. Core Features
|
||||
|
||||
The Mounter provides a comprehensive set of features making it a versatile
|
||||
solution:
|
||||
|
||||
* **Broad OS Compatibility**: Full support for Kickstart 1.3 and newer,
|
||||
including its specific autoboot mechanisms.
|
||||
* **CPU Compatibility**: Compatible with the Motorola 68000 processor, ensuring
|
||||
it runs on all classic Amiga models.
|
||||
* **Autoboot Capability**: Can participate in the Amiga's autoconfig boot
|
||||
process to mount bootable partitions
|
||||
* **Full Automount Support**: Automatically finds and mounts all valid
|
||||
partitions it discovers.
|
||||
* **Rich Filesystem Support**:
|
||||
* **RDB**: Full support for the Amiga Rigid Disk Block (RDB) standard.
|
||||
* **MBR & GPT**: Support for PC-style Master Boot Record and GUID Partition
|
||||
Table layouts, enhancing cross-platform compatibility.
|
||||
* **CD-ROM**: Capable of booting from CD-ROMs following the ISO 9660
|
||||
standard with Amiga-specific "Amiga Boot" or "CDTV" system identifiers.
|
||||
* **LUN Support**: Can scan for and mount devices on multiple Logical Unit
|
||||
Numbers (LUNs).
|
||||
|
||||
---
|
||||
|
||||
## 3. High-Level Architecture
|
||||
|
||||
The Mounter's architecture is centered around a single primary entry point,
|
||||
`MountDrive()`, which orchestrates the entire mounting process. It operates
|
||||
by opening a specified device driver, scanning its units, and attempting to
|
||||
identify and mount partitions.
|
||||
|
||||
### 3.1. Key Data Structures
|
||||
|
||||
* **`struct MountStruct` (`mounter.h`)**: This is the main input structure
|
||||
passed to the `MountDrive` function. It defines the parameters for a mounting
|
||||
session.
|
||||
* `deviceName`: The name of the device driver to use (e.g., `scsi.device`).
|
||||
* `unitNum`: A pointer to an array of unit numbers to scan.
|
||||
* `creatorName`: A string to identify the creator of the filesystem entries.
|
||||
* `configDev`: A pointer to the `ConfigDev` structure for an autoconfig
|
||||
board, essential for autobooting.
|
||||
* `luns`, `slowSpinup`, `cdBoot`, `ignoreLast`: Boolean flags to control
|
||||
behavior like LUN scanning, spin-up delays, CD booting, and handling of
|
||||
the RDB `RDBFF_LAST` flag.
|
||||
* `SysBase`: A pointer to the Exec library base.
|
||||
|
||||
* **`struct MountData` (`mounter.c`)**: An internal state-management structure
|
||||
used during the `MountDrive` execution. It holds pointers to opened
|
||||
libraries, the I/O request, device geometry, and state variables for the
|
||||
scanning process.
|
||||
|
||||
### 3.2. Control Flow
|
||||
|
||||
The logical flow of the `MountDrive` function is as follows:
|
||||
|
||||
1. **Initialization**:
|
||||
* Allocate a `MountData` structure to hold operational state.
|
||||
* Open required system libraries (`expansion.library`, `dos.library`).
|
||||
* Create a message port and an I/O request for communicating with the
|
||||
device driver.
|
||||
|
||||
2. **Device Scanning Loop**:
|
||||
* Iterate through the specified SCSI targets (and LUNs, if enabled).
|
||||
* For each unit, attempt to `OpenDevice()`.
|
||||
|
||||
3. **Partition Scheme Identification**:
|
||||
* If a device is opened successfully, get its geometry using
|
||||
`TD_GETGEOMETRY`.
|
||||
* Based on the device type (`DG_DIRECT_ACCESS`, `DG_CDROM`), determine
|
||||
the scanning strategy.
|
||||
* **For Direct Access Devices**:
|
||||
1. Attempt to find an RDB by scanning the first `RDB_LOCATION_LIMIT`
|
||||
blocks (`ScanRDSK`).
|
||||
2. If no RDB is found, check for a GUID Partition Table (GPT) at
|
||||
block 1 (`ScanMBR`).
|
||||
3. If no GPT is found, check for a Master Boot Record (MBR) at block
|
||||
0 (`ScanMBR`).
|
||||
* **For CD-ROM Devices**:
|
||||
1. Check if the unit is ready and contains a data CD (`ScanCDROM`).
|
||||
2. Check the Primary Volume Descriptor (PVD) for "AMIGA BOOT" or
|
||||
"CDTV" identifiers (`CheckPVD`).
|
||||
3. If not an Amiga bootable CD, fall back to scanning for an RDB
|
||||
(`ScanRDSK`).
|
||||
|
||||
4. **Partition Processing**:
|
||||
* Call the appropriate parsing function (`ParseRDSK`, `ParseGPT`,
|
||||
`ParseMBR`, `ScanCDROM`).
|
||||
* These functions iterate through partition entries.
|
||||
|
||||
5. **Filesystem Loading & Mounting**:
|
||||
* For each valid partition, `ParsePART` is called.
|
||||
* It reads the partition's `DosEnvec` to determine the required filesystem
|
||||
`DosType`.
|
||||
* It calls `ParseFSHD` to find or load the required filesystem. `ParseFSHD`
|
||||
searches `FileSystem.resource` and, if not found or if the version is
|
||||
older, loads the filesystem from the disk's FileSystem Header Blocks
|
||||
(`FSHD`).
|
||||
* The loaded filesystem code is relocated in memory using the `fsrelocate`
|
||||
function.
|
||||
* A `DeviceNode` is created using `MakeDosNode()` and populated with the
|
||||
partition's parameters.
|
||||
* The `DeviceNode` is added to the system's mount list using `AddDosNode()`
|
||||
or `AddBootNode()` (for bootable partitions).
|
||||
|
||||
6. **Cleanup**:
|
||||
* The device is closed.
|
||||
* The loop continues to the next unit/target.
|
||||
* After the loop, all allocated resources (I/O requests, ports, library
|
||||
bases) are freed.
|
||||
|
||||
---
|
||||
|
||||
## 4. Core Functionality Details
|
||||
|
||||
### 4.1. Filesystem Relocation (`fsrelocate`)
|
||||
|
||||
A critical function is `fsrelocate`, which loads Amiga HUNK-formatted
|
||||
filesystem binaries from disk into memory.
|
||||
1. It starts by reading a `HUNK_HEADER`.
|
||||
2. It pre-allocates memory for all hunks (`HUNK_CODE`, `HUNK_DATA`,
|
||||
`HUNK_BSS`) defined in the header.
|
||||
3. It reads each hunk's data from the LSEG (Load Segment) blocks on disk.
|
||||
4. It processes relocation hunks (`HUNK_RELOC32`) to resolve memory address
|
||||
pointers within the loaded code and data, making the filesystem executable
|
||||
from its new location in RAM.
|
||||
5. Finally, it performs a `CacheClearU()` to ensure instruction caches are
|
||||
flushed before the OS attempts to execute the newly loaded code.
|
||||
|
||||
### 4.2. Filesystem Resource Management (`FSHDProcess`, `FSHDAdd`)
|
||||
|
||||
The mounter interacts carefully with the central `FileSystem.resource`.
|
||||
* `FSHDProcess` is responsible for checking if a required filesystem
|
||||
(identified by `DosType`) is already present in the resource list.
|
||||
* If a filesystem is not present, or if the version on disk is newer than the
|
||||
one in memory, it allocates a new `FileSysEntry`.
|
||||
* After a filesystem is successfully loaded and relocated by `fsrelocate`,
|
||||
`FSHDAdd` adds the new `FileSysEntry` to `FileSystem.resource`,
|
||||
making it available for all subsequent mounting operations
|
||||
system-wide.
|
||||
* If `FileSystem.resource` does not exist (common on KS 1.3), it is created.
|
||||
|
||||
### 4.3. Kickstart 1.3 Compatibility
|
||||
|
||||
To maintain compatibility with Kickstart 1.3, which lacks certain OS functions,
|
||||
the mounter includes its own implementations:
|
||||
* `W_CreateMsgPort` / `W_DeleteMsgPort`
|
||||
* `W_CreateIORequest` / `W_DeleteIORequest`
|
||||
|
||||
These functions use `AllocMem()` to create the necessary structures and manage
|
||||
signals manually, mimicking the behavior of their modern counterparts. For
|
||||
autobooting, it manually creates and inserts a `BootNode` into the
|
||||
`expansion.library`'s `MountList`, as `AddBootNode` is not fully featured on KS
|
||||
1.3.
|
||||
|
||||
### 4.4. Autoboot Process
|
||||
|
||||
When a bootable partition is found and the mounter is operating in an autoboot
|
||||
context (i.e., a `configDev` is provided), it uses `AddBootNode()` instead of
|
||||
`AddDosNode()`. This function links the mountable partition directly to the
|
||||
autoconfig hardware board, signaling to the OS that this is a candidate for
|
||||
booting. If no `configDev` is provided, the mounter can create a "fake" one to
|
||||
enable autobooting from devices that are not on a standard autoconfig chain.
|
||||
|
||||
---
|
||||
|
||||
## 5. Dependencies
|
||||
|
||||
The Mounter relies on the following standard AmigaOS libraries:
|
||||
|
||||
* `exec.library` (v34+): For memory management, tasking, ports, and core system
|
||||
functions.
|
||||
* `expansion.library` (v34+): For adding boot nodes and interacting with the
|
||||
autoconfig process.
|
||||
* `dos.library` (v34+): For creating `DeviceNode` structures and adding them
|
||||
to the DOS list.
|
||||
|
||||
---
|
||||
|
||||
## 6. License
|
||||
|
||||
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.
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,19 +1,16 @@
|
||||
#ifndef MOUNTER_H
|
||||
#define MOUNTER_H
|
||||
|
||||
struct UnitStruct
|
||||
{
|
||||
ULONG unitNum;
|
||||
struct ConfigDev *configDev;
|
||||
};
|
||||
|
||||
struct MountStruct
|
||||
{
|
||||
// Device name. ("myhddriver.device")
|
||||
// Offset 0.
|
||||
UBYTE *deviceName;
|
||||
// Number of units
|
||||
UWORD numUnits;
|
||||
const UBYTE *deviceName;
|
||||
// Unit number pointer or single integer value.
|
||||
// if >= 0x100 (256), pointer to array of ULONGs, first ULONG is number of unit numbers followed (for example { 2, 0, 1 }. 2 units, unit numbers 0 and 1).
|
||||
// if < 0x100 (256): used as a single unit number value.
|
||||
// Offset 4.
|
||||
ULONG *unitNum;
|
||||
// Name string used to set Creator field in FileSystem.resource (if KS 1.3) and in FileSystem.resource entries.
|
||||
// If NULL: use device name.
|
||||
// Offset 8.
|
||||
@ -25,17 +22,23 @@ struct MountStruct
|
||||
// SysBase.
|
||||
// Offset 16.
|
||||
struct ExecBase *SysBase;
|
||||
// Array of UnitStructs
|
||||
struct UnitStruct Units[];
|
||||
// LUNs
|
||||
// Offset 20.
|
||||
BOOL luns;
|
||||
// Short/Long Spinup
|
||||
// Offset 22.
|
||||
BOOL slowSpinup;
|
||||
// Enahle CD Boot
|
||||
BOOL cdBoot;
|
||||
// Ignore RDBFF_LAST flag
|
||||
BOOL ignoreLast;
|
||||
};
|
||||
|
||||
|
||||
APTR W_CreateIORequest(struct MsgPort *ioReplyPort, ULONG size, struct ExecBase *SysBase);
|
||||
void W_DeleteIORequest(APTR iorequest, struct ExecBase *SysBase);
|
||||
struct MsgPort *W_CreateMsgPort(struct ExecBase *SysBase);
|
||||
void W_DeleteMsgPort(struct MsgPort *port, struct ExecBase *SysBase);
|
||||
|
||||
int mount_drives(struct ConfigDev *cd, char *devName, struct MountStruct *ms);
|
||||
LONG MountDrive(struct MountStruct *ms);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
31
mounter/ndkcompat.h
Normal file
31
mounter/ndkcompat.h
Normal file
@ -0,0 +1,31 @@
|
||||
//
|
||||
// Copyright 2022-2025 Stefan Reinauer
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef __NDK_COMPAT_H
|
||||
#define __NDK_COMPAT_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/* ULONG has changed from NDK 3.9 to NDK 3.2.
|
||||
* However, PRI*32 did not. What is the right way to implement this?
|
||||
*/
|
||||
#if INCLUDE_VERSION < 47
|
||||
#undef PRIu32
|
||||
#define PRIu32 "lu"
|
||||
#undef PRId32
|
||||
#define PRId32 "ld"
|
||||
#undef PRIx32
|
||||
#define PRIx32 "lx"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
18
ndkcompat.h
18
ndkcompat.h
@ -1,18 +0,0 @@
|
||||
#ifndef __NDK_COMPAT_H
|
||||
#define __NDK_COMPAT_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/* ULONG has changed from NDK 3.9 to NDK 3.2.
|
||||
* However, PRI*32 did not. What is the right way to implement this?
|
||||
*/
|
||||
#if INCLUDE_VERSION < 47
|
||||
#undef PRIu32
|
||||
#define PRIu32 "lu"
|
||||
#undef PRId32
|
||||
#define PRId32 "ld"
|
||||
#undef PRIx32
|
||||
#define PRIx32 "lx"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Loading…
x
Reference in New Issue
Block a user