mirror of
https://github.com/LIV2/lide.device.git
synced 2025-12-06 00:32:45 +00:00
959 lines
26 KiB
C
959 lines
26 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/* This file is part of lideflash
|
|
* Copyright (C) 2023 Matthew Harlum <matt@harlum.net>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; version 2.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
* See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include <exec/execbase.h>
|
|
#include <exec/errors.h>
|
|
#include <proto/exec.h>
|
|
#include <proto/expansion.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdbool.h>
|
|
#include <proto/dos.h>
|
|
#include <dos/dos.h>
|
|
#include <proto/alib.h>
|
|
#include <dos/dosextens.h>
|
|
#include <intuition/intuitionbase.h>
|
|
#include <proto/intuition.h>
|
|
|
|
#include "flash.h"
|
|
#include "main.h"
|
|
#include "config.h"
|
|
#include "matzetk.h"
|
|
#include "../device.h"
|
|
#include "../iotask.h"
|
|
|
|
#define MANUF_ID_BSC 0x082C
|
|
#define MANUF_ID_OAHR 5194
|
|
|
|
#define PROD_ID_CIDER 0x05
|
|
#define PROD_ID_RIPPLE 0x07
|
|
#define PROD_ID_RIDE 0x09
|
|
|
|
#define SERIAL_LIV2 0x4C495632
|
|
|
|
#define ROMSIZE 32768
|
|
|
|
const char ver[] = VERSION_STRING;
|
|
|
|
struct Library *DosBase;
|
|
struct ExecBase *SysBase;
|
|
struct ExpansionBase *ExpansionBase = NULL;
|
|
struct Config *config;
|
|
bool devsInhibited = false;
|
|
|
|
void bankSelect(UBYTE bank, struct ideBoard *board);
|
|
|
|
/**
|
|
* _ColdReboot()
|
|
*
|
|
* Kickstart V36 (2.0+) and up contain a function for this
|
|
* But for 1.3 we will need to provide our own function
|
|
*/
|
|
static void _ColdReboot() {
|
|
// Copied from coldboot.asm
|
|
// http://amigadev.elowar.com/read/ADCD_2.1/Hardware_Manual_guide/node02E3.html
|
|
asm("move.l 4,a6 \n\t" // SysBase
|
|
"lea.l DoIt(pc),a5 \n\t"
|
|
"jsr -0x1e(a6) \n\t" // Call from Supervisor mode
|
|
".align 4 \n\t" // Must be aligned!
|
|
"DoIt: \n\t"
|
|
"lea.l 0x1000000,a0 \n\t" // (ROM end)
|
|
"sub.l -0x14(a0),a0 \n\t" // (ROM end)-(ROM Size)
|
|
"move.l 4(a0),a0 \n\t" // Initial PC
|
|
"subq.l #2,(a0) \n\t" // Points to second RESET
|
|
"reset \n\t"
|
|
"jmp (a0)");
|
|
}
|
|
|
|
/**
|
|
* inhibitDosDevs
|
|
*
|
|
* inhibit/uninhibit all drives
|
|
* Some boards lock out IDE when flash mode is enabled
|
|
* Send an ACTION_INHIBIT packet to all devices to flush the buffers to disk first
|
|
*
|
|
* @param inhibit (bool) True: inhibit, False: uninhibit
|
|
*/
|
|
bool inhibitDosDevs(bool inhibit) {
|
|
bool success = true;
|
|
struct MsgPort *mp = CreatePort(NULL,0);
|
|
struct Message msg;
|
|
struct DosPacket __aligned packet;
|
|
struct DosList *dl;
|
|
struct dosDev *dd;
|
|
|
|
struct MinList devs;
|
|
NewList((struct List *)&devs);
|
|
|
|
if (mp) {
|
|
packet.dp_Port = mp;
|
|
packet.dp_Link = &msg;
|
|
msg.mn_Node.ln_Name = (char *)&packet;
|
|
|
|
if (SysBase->LibNode.lib_Version >= 36) {
|
|
|
|
dl = LockDosList(LDF_DEVICES|LDF_READ);
|
|
// Build a list of dos devices to inhibit
|
|
// We need to send a packet to the FS to do the inhibit after releasing the lock
|
|
// So build a list of devs to be (un)-inhibited
|
|
while ((dl = NextDosEntry(dl,LDF_DEVICES))) {
|
|
dd = AllocMem(sizeof(struct dosDev),MEMF_ANY|MEMF_CLEAR);
|
|
if (dd) {
|
|
if (dl->dol_Task) { // Device has a FS process?
|
|
dd->handler = dl->dol_Task;
|
|
AddTail((struct List *)&devs,(struct Node *)dd);
|
|
}
|
|
}
|
|
}
|
|
UnLockDosList(LDF_DEVICES|LDF_READ);
|
|
|
|
} else {
|
|
// For Kickstart 1.3
|
|
// Build a list of dos devices the old fashioned way
|
|
struct RootNode *rn = DOSBase->dl_Root;
|
|
struct DosInfo *di = BADDR(rn->rn_Info);
|
|
|
|
Forbid();
|
|
// Build a list of dos devices to inhibit
|
|
// We need to send a packet to the FS but that can't be done while in Forbid()
|
|
// So build a list of devs to be (un)-inhibited
|
|
for (dl = BADDR(di->di_DevInfo); dl; dl = BADDR(dl->dol_Next)) {
|
|
if (dl->dol_Type == DLT_DEVICE && dl->dol_Task) {
|
|
dd = AllocMem(sizeof(struct dosDev),MEMF_ANY|MEMF_CLEAR);
|
|
if (dd) {
|
|
if (dl->dol_Task) { // Device has a FS process?
|
|
dd->handler = dl->dol_Task;
|
|
AddTail((struct List *)&devs,(struct Node *)dd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Permit();
|
|
}
|
|
|
|
struct dosDev *next = NULL;
|
|
// Send an ACTION_INHIBIT packet directly to the FS
|
|
for (dd = (struct dosDev *)devs.mlh_Head; dd->mn.mln_Succ; dd = next) {
|
|
if (inhibit) {
|
|
packet.dp_Port = mp;
|
|
packet.dp_Type = ACTION_FLUSH;
|
|
PutMsg(dd->handler,&msg);
|
|
WaitPort(mp);
|
|
GetMsg(mp);
|
|
}
|
|
|
|
for (int t=0; t < 3; t++) {
|
|
packet.dp_Port = mp;
|
|
packet.dp_Type = ACTION_INHIBIT;
|
|
packet.dp_Arg1 = (inhibit) ? DOSTRUE : DOSFALSE;
|
|
PutMsg(dd->handler,&msg);
|
|
WaitPort(mp);
|
|
GetMsg(mp);
|
|
|
|
if (packet.dp_Res1 == DOSTRUE || packet.dp_Res2 == ERROR_ACTION_NOT_KNOWN)
|
|
break;
|
|
|
|
Delay(1*TICKS_PER_SECOND);
|
|
}
|
|
|
|
if (packet.dp_Res1 == DOSFALSE && packet.dp_Res2 != ERROR_ACTION_NOT_KNOWN) {
|
|
success = false;
|
|
}
|
|
|
|
next = (struct dosDev *)dd->mn.mln_Succ;
|
|
Remove((struct Node *)dd);
|
|
FreeMem(dd,sizeof(struct dosDev));
|
|
|
|
}
|
|
|
|
DeletePort(mp);
|
|
|
|
} else {
|
|
success = false;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
/**
|
|
* suspend_lide
|
|
*
|
|
* Send a CMD_PAUSE/CMD_RESUME command to every running instance of lide.device
|
|
* This is used to pause the lide IO task while we disable the IDE interface
|
|
*
|
|
* @param pause (bool) True to pause, False to resume
|
|
*/
|
|
void suspend_lide(bool pause) {
|
|
struct MsgPort *mp = NULL;
|
|
struct IOStdReq *ior = NULL;
|
|
|
|
BYTE err = 0;
|
|
|
|
const char device_name[] = DEVICE_NAME;
|
|
const ULONG prefix[] = {' nd.', ' rd.', ' th.'};
|
|
char *prefixedName;
|
|
char *devNamePtr;
|
|
|
|
if ((prefixedName = AllocMem(sizeof(device_name) + 4,MEMF_ANY|MEMF_CLEAR))) {
|
|
memcpy(prefixedName+4,device_name,sizeof(device_name));
|
|
if ((mp = CreatePort(NULL,0))) {
|
|
if ((ior = CreateStdIO(mp))) {
|
|
// Iterate through device names from lide.device .. 8th.lide.device
|
|
for (int i=0; i < 8; i++) {
|
|
switch (i) {
|
|
case 0: // lide.device
|
|
devNamePtr = prefixedName + 4;
|
|
break;
|
|
case 1: // 2nd.lide.device
|
|
devNamePtr = prefixedName;
|
|
*(ULONG *)devNamePtr = prefix[0];
|
|
break;
|
|
case 2: // 3rd.lide.device
|
|
devNamePtr = prefixedName;
|
|
*(ULONG *)devNamePtr = prefix[1];
|
|
break;
|
|
default: // 4-8th.lide.device
|
|
devNamePtr = prefixedName;
|
|
*(ULONG *)devNamePtr = prefix[2];
|
|
break;
|
|
}
|
|
|
|
// Set the prefix number
|
|
if (i > 0) *(char *)prefixedName = '1' + i;
|
|
|
|
// DOS Devices are inhibited so check that the device is already loaded
|
|
// OpenDevice would otherwise try to load from disk which would throw a requester
|
|
if (FindName(&SysBase->DeviceList,devNamePtr)) {
|
|
for (int unit=0; unit < MAX_UNITS; unit++) {
|
|
err = OpenDevice(devNamePtr,unit,(struct IORequest *)ior,0);
|
|
|
|
if (err == IOERR_OPENFAIL) break;
|
|
|
|
if (err == 0) {
|
|
ior->io_Command = (pause) ? CMD_PAUSE : CMD_RESUME;
|
|
ior->io_Error = 0;
|
|
err = DoIO((struct IORequest *)ior);
|
|
CloseDevice((struct IORequest *)ior);
|
|
|
|
if (err == IOERR_NOCMD) break;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
DeleteStdIO(ior);
|
|
}
|
|
DeletePort(mp);
|
|
}
|
|
FreeMem(prefixedName,sizeof(device_name) + 4);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* setup_liv2_board
|
|
*
|
|
* Configure the board struct for a LIV2 Board (CIDER/RIPPLE)
|
|
* @param board pointer to the board struct
|
|
*/
|
|
static void setup_liv2_board(struct ideBoard *board) {
|
|
board->bootrom = CIDER;
|
|
board->bankSelect = &bankSelect;
|
|
board->writeEnable = NULL;
|
|
board->rebootRequired = false;
|
|
|
|
board->flashbase = board->cd->cd_BoardAddr;
|
|
|
|
if (board->cd->cd_BoardSize > 65536) {
|
|
// Newer version of the CIDER & RIPPLE firmware give the IDE device a 128K block, with the top 64K dedicated to the Flash
|
|
// This means we can flash the IDE ROM without having to disable IDE
|
|
board->flashbase += 65536;
|
|
}
|
|
|
|
if (board->cd->cd_Driver == NULL) {
|
|
// Poke IDE register space to ensure ROM overlay turned off
|
|
UBYTE *pokeReg = (UBYTE *)(board->cd->cd_BoardAddr + 0x1200);
|
|
*pokeReg = 0x00;
|
|
}
|
|
|
|
switch (board->cd->cd_Rom.er_Product) {
|
|
case PROD_ID_RIPPLE:
|
|
board->banks = 2;
|
|
break;
|
|
case PROD_ID_RIDE:
|
|
board->banks = 4;
|
|
break;
|
|
default:
|
|
board->banks = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* promptUser
|
|
*
|
|
* 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, bool update) {
|
|
int c;
|
|
char answer = 'y'; // Default to yes
|
|
|
|
if (update) {
|
|
printf("Update this device?");
|
|
} else {
|
|
printf("Erase flash?");
|
|
}
|
|
printf(" (Y)es/(n)o/(a)ll: ");
|
|
|
|
if (config->assumeYes) {
|
|
printf("y\n");
|
|
return true;
|
|
}
|
|
|
|
while ((c = getchar()) != '\n' && c != EOF) answer = c;
|
|
|
|
answer |= 0x20; // convert to lowercase;
|
|
|
|
if (answer == 'a') {
|
|
config->assumeYes = true;
|
|
return true;
|
|
}
|
|
|
|
return (answer == 'y');
|
|
}
|
|
|
|
/**
|
|
* assemble_rom
|
|
*
|
|
* 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) {
|
|
if (!src_buffer || !dst_buffer || bufSize == 0) return;
|
|
|
|
char *bootstrap = NULL;
|
|
char *driver = NULL;
|
|
|
|
enum BOOTROM srcRomType = (((ULONG *)src_buffer)[0] == SERIAL_LIV2) ? CIDER : ATBUS;
|
|
|
|
memset(dst_buffer,0xFF,bufSize);
|
|
|
|
if (srcRomType == dstRomType) {
|
|
CopyMem(src_buffer,dst_buffer,bufSize);
|
|
} else {
|
|
driver = src_buffer + 0x1000;
|
|
|
|
if (dstRomType == ATBUS) {
|
|
// Source file was lide.rom, remove the 'LIV2' header
|
|
bootstrap = src_buffer + 4;
|
|
CopyMem(bootstrap,dst_buffer,0x1000);
|
|
} else {
|
|
// Source file was lide-atbus.rom, add the 'LIV2' header
|
|
((ULONG *)dst_buffer)[0] = SERIAL_LIV2;
|
|
CopyMem(src_buffer,dst_buffer + 4, 0xFFC);
|
|
}
|
|
|
|
CopyMem(driver,dst_buffer + 0x1000, bufSize - 0x1000);
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
DosBase = OpenLibrary("dos.library",0);
|
|
|
|
int rc = 0;
|
|
int boards_found = 0;
|
|
|
|
void *driver_buffer = NULL;
|
|
void *driver_buffer2 = NULL;
|
|
void *misc_buffer = NULL;
|
|
|
|
char *ver = NULL;
|
|
|
|
ULONG romSize = 0;
|
|
ULONG miscSize = 0;
|
|
|
|
if (DosBase == NULL) {
|
|
return(rc);
|
|
}
|
|
|
|
// Throw an alert if Kick < 1.3
|
|
if (SysBase->LibNode.lib_Version < 34) {
|
|
struct IntuitionBase *IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
|
|
|
|
// Screen mode is 64 columns with a 10x8 font
|
|
char AlertString[] = {
|
|
"\x00\x82" // X coord
|
|
"\x10" // Y coord
|
|
"LIDE requires Kickstart 1.3 or higher!"
|
|
"\x00\x01" // Continue
|
|
"\x00\x64" // X coord
|
|
"\x1A" // Y coord
|
|
"Please upgrade to a newer Kickstart version"
|
|
"\x00\x01" // Continue
|
|
"\x00\x8C" // X coord
|
|
"\x2E" // Y coord
|
|
"Press left mouse button to continue."
|
|
"\x00\x00"
|
|
};
|
|
|
|
DisplayAlert(0,AlertString,58);
|
|
CloseLibrary((struct Library *)IntuitionBase);
|
|
}
|
|
|
|
printf("\n==== LIDE Flash Updater ====\n");
|
|
|
|
struct Task *task = FindTask(0);
|
|
SetTaskPri(task,20);
|
|
if ((config = configure(argc,argv)) != NULL) {
|
|
|
|
if (config->ide_rom_filename) {
|
|
romSize = getFileSize(config->ide_rom_filename);
|
|
if (romSize == 0) {
|
|
rc = 5;
|
|
goto exit;
|
|
}
|
|
|
|
if (romSize > 32768) {
|
|
printf("ROM file too large.\n");
|
|
rc = 5;
|
|
goto exit;
|
|
}
|
|
|
|
if (romSize < 4096) {
|
|
printf("ROM file too small.\n");
|
|
rc = 5;
|
|
goto exit;
|
|
}
|
|
|
|
driver_buffer = AllocMem(romSize,MEMF_ANY|MEMF_CLEAR);
|
|
driver_buffer2 = AllocMem(romSize,MEMF_ANY|MEMF_CLEAR);
|
|
|
|
if (driver_buffer && driver_buffer2) {
|
|
if (readFileToBuf(config->ide_rom_filename,driver_buffer) == false) {
|
|
rc = 5;
|
|
goto exit;
|
|
}
|
|
} else {
|
|
printf("Couldn't allocate memory.\n");
|
|
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) {
|
|
|
|
miscSize = getFileSize(config->misc_filename);
|
|
|
|
if (miscSize == 0) {
|
|
rc = 5;
|
|
goto exit;
|
|
}
|
|
|
|
if (miscSize > 32768) {
|
|
printf("File too large!\n");
|
|
rc = 5;
|
|
goto exit;
|
|
}
|
|
|
|
misc_buffer = AllocMem(miscSize,MEMF_ANY|MEMF_CLEAR);
|
|
if (misc_buffer) {
|
|
if (readFileToBuf(config->misc_filename,misc_buffer) == false) {
|
|
rc = 5;
|
|
goto exit;
|
|
}
|
|
} else {
|
|
printf("Couldn't allocate memory.\n");
|
|
rc = 5;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
if (!inhibitDosDevs(true)) {
|
|
printf("Failed to inhibit AmigaDOS volumes, wait for disk activity to stop and try again.\n");
|
|
rc = 5;
|
|
inhibitDosDevs(false);
|
|
goto exit;
|
|
};
|
|
|
|
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;
|
|
|
|
switch (cd->cd_Rom.er_Manufacturer) {
|
|
case MANUF_ID_OAHR:
|
|
if (cd->cd_Rom.er_Product == PROD_ID_CIDER) {
|
|
printf("Found CIDER IDE");
|
|
setup_liv2_board(&board);
|
|
break;
|
|
} else if (cd->cd_Rom.er_Product == PROD_ID_RIPPLE) {
|
|
printf("Found RIPPLE IDE");
|
|
setup_liv2_board(&board);
|
|
break;
|
|
} else if (cd->cd_Rom.er_Product == PROD_ID_RIDE) {
|
|
printf("Found RIDE IDE");
|
|
setup_liv2_board(&board);
|
|
break;
|
|
} else {
|
|
continue; // Skip this board
|
|
}
|
|
|
|
case MANUF_ID_A1K:
|
|
if (cd->cd_Rom.er_Product == PROD_ID_MATZE_IDE &&
|
|
cd->cd_Rom.er_SerialNumber == SERIAL_MATZE) {
|
|
|
|
if (boardIsOlga(cd)) {
|
|
printf("Found Dicke Olga");
|
|
|
|
if (!matzetk_fw_supported(cd,OLGA_MIN_FW_VER,false)) {
|
|
continue;
|
|
}
|
|
|
|
setup_matzetk_board(&board);
|
|
break;
|
|
|
|
} else if (boardIs68ec020tk(cd)) {
|
|
printf("Found 68EC020-TK");
|
|
|
|
if (!matzetk_fw_supported(cd,TK020_MIN_FW_VER,false)) {
|
|
continue;
|
|
}
|
|
|
|
setup_matzetk_board(&board);
|
|
break;
|
|
} else if (boardIsZorroLanIDE(cd)) {
|
|
if (!matzetk_fw_supported(cd,LAN_IDE_MIN_FW_VER,true)) {
|
|
continue;
|
|
}
|
|
|
|
printf("Found Zorro-LAN-IDE");
|
|
|
|
setup_matzetk_board(&board);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
case MANUF_ID_BSC:
|
|
if (cd->cd_Rom.er_Product == 6) {
|
|
// Is it a LIV2 board pretending to be an AT-Bus 2008?
|
|
if (cd->cd_Rom.er_SerialNumber == SERIAL_LIV2) {
|
|
printf("Found Unknown LIV2 IDE board");
|
|
setup_liv2_board(&board);
|
|
break;
|
|
} else if (cd->cd_Rom.er_SerialNumber == SERIAL_MATZE) {
|
|
|
|
if (boardIsOlga(cd)) {
|
|
printf("Found Dicke Olga");
|
|
|
|
if (!matzetk_fw_supported(cd,OLGA_MIN_FW_VER,false)) {
|
|
continue;
|
|
}
|
|
|
|
setup_matzetk_board(&board);
|
|
break;
|
|
|
|
} else if (boardIs68ec020tk(cd)) {
|
|
printf("Found 68EC020-TK");
|
|
|
|
if (!matzetk_fw_supported(cd,TK020_MIN_FW_VER,false)) {
|
|
continue;
|
|
}
|
|
|
|
setup_matzetk_board(&board);
|
|
break;
|
|
} else if (boardIsZorroLanIDE(cd)) {
|
|
if (!matzetk_fw_supported(cd,LAN_IDE_MIN_FW_VER,true)) {
|
|
continue;
|
|
}
|
|
|
|
printf("Found Zorro-LAN-IDE");
|
|
|
|
setup_matzetk_board(&board);
|
|
break;
|
|
}
|
|
}
|
|
|
|
continue; // Skip this board
|
|
}
|
|
|
|
default:
|
|
continue; // Skip this board
|
|
}
|
|
|
|
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, update)) continue;
|
|
|
|
suspend_lide(true);
|
|
|
|
if (board.writeEnable != NULL) // Setup board to allow flash write access
|
|
board.writeEnable(&board);
|
|
|
|
if (board.rebootRequired)
|
|
config->rebootRequired = true;
|
|
|
|
UBYTE manufId,devId;
|
|
UWORD sectorSize;
|
|
|
|
if (flash_init(&manufId,&devId,board.flashbase,§orSize)) {
|
|
if (config->eraseFlash) {
|
|
printf("Erasing flash.\n");
|
|
flash_erase_chip();
|
|
}
|
|
|
|
if (config->ide_rom_filename) {
|
|
if (board.bankSelect != NULL) {
|
|
board.bankSelect(0,&board);
|
|
}
|
|
|
|
if (config->eraseFlash == false) {
|
|
if (sectorSize > 0) {
|
|
printf("Erasing IDE bank...\n");
|
|
flash_erase_bank(sectorSize);
|
|
} else {
|
|
printf("Erasing IDE flash...\n");
|
|
flash_erase_chip();
|
|
}
|
|
}
|
|
printf("Writing IDE ROM.\n");
|
|
assemble_rom(driver_buffer,driver_buffer2,romSize,board.bootrom);
|
|
writeBufToFlash(&board,driver_buffer2,board.flashbase,romSize);
|
|
printf("\n");
|
|
}
|
|
|
|
if (config->misc_filename) {
|
|
|
|
if (config->misc_bank < board.banks && sectorSize > 0) {
|
|
|
|
if (board.bankSelect != NULL)
|
|
board.bankSelect(config->misc_bank,&board);
|
|
|
|
if (config->eraseFlash == false) {
|
|
printf("Erasing bank %d...\n",config->misc_bank);
|
|
flash_erase_bank(sectorSize);
|
|
}
|
|
printf("Writing bank %d.\n",config->misc_bank);
|
|
writeBufToFlash(&board,misc_buffer,board.flashbase,miscSize);
|
|
} else {
|
|
printf("This board does not support flashing bank %d.\n",config->misc_bank);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
printf("Error: IDE - Unknown Flash device Manufacturer: %02X Device: %02X\n", manufId, devId);
|
|
if (cd->cd_BoardSize == 65535) {
|
|
printf("Turn IDE off and try again.\n");
|
|
}
|
|
rc = 5;
|
|
}
|
|
}
|
|
|
|
if (boards_found == 0) {
|
|
printf("No IDE board(s) found\n");
|
|
}
|
|
} else {
|
|
printf("Couldn't open Expansion.library.\n");
|
|
rc = 5;
|
|
}
|
|
|
|
if (config->rebootRequired) {
|
|
printf("Press return to reboot.\n");
|
|
getchar();
|
|
if (SysBase->LibNode.lib_Version >= 36) {
|
|
ColdReboot();
|
|
} else {
|
|
_ColdReboot();
|
|
}
|
|
}
|
|
|
|
suspend_lide(false);
|
|
if (devsInhibited)
|
|
inhibitDosDevs(false);
|
|
|
|
} else {
|
|
usage();
|
|
}
|
|
|
|
exit:
|
|
if (driver_buffer2) FreeMem(driver_buffer2,romSize);
|
|
if (driver_buffer) FreeMem(driver_buffer,romSize);
|
|
if (misc_buffer) FreeMem(misc_buffer,miscSize);
|
|
if (config) FreeMem(config,sizeof(struct Config));
|
|
if (ExpansionBase) CloseLibrary((struct Library *)ExpansionBase);
|
|
if (DosBase) CloseLibrary((struct Library *)DosBase);
|
|
return (rc);
|
|
}
|
|
|
|
/**
|
|
* getFileSize
|
|
*
|
|
* @brief return the size of a file in bytes
|
|
* @param filename file to check the size of
|
|
* @returns File size in bytes
|
|
*/
|
|
ULONG getFileSize(char *filename) {
|
|
BPTR fileLock;
|
|
ULONG fileSize = 0;
|
|
struct FileInfoBlock *FIB;
|
|
|
|
FIB = (struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),MEMF_CLEAR);
|
|
|
|
if ((fileLock = Lock(filename,ACCESS_READ)) != 0) {
|
|
|
|
if (Examine(fileLock,FIB)) {
|
|
fileSize = FIB->fib_Size;
|
|
}
|
|
|
|
} else {
|
|
printf("Error opening %s\n",filename);
|
|
fileSize = 0;
|
|
}
|
|
|
|
if (fileLock) UnLock(fileLock);
|
|
if (FIB) FreeMem(FIB,sizeof(struct FileInfoBlock));
|
|
|
|
return (fileSize);
|
|
}
|
|
|
|
/**
|
|
* readFileToBuF
|
|
*
|
|
* @brief Read the rom file to a buffer
|
|
* @param filename Name of the file to open
|
|
* @return true on success
|
|
*/
|
|
BOOL readFileToBuf(char *filename, void *buffer) {
|
|
ULONG romSize = getFileSize(filename);
|
|
BOOL ret = true;
|
|
|
|
if (romSize == 0) return false;
|
|
|
|
BPTR fh;
|
|
|
|
if (buffer) {
|
|
fh = Open(filename,MODE_OLDFILE);
|
|
|
|
if (fh) {
|
|
Read(fh,buffer,romSize);
|
|
Close(fh);
|
|
} else {
|
|
printf("Error opening %s\n",filename);
|
|
return false;
|
|
}
|
|
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* bankSelect
|
|
*
|
|
* Select a bank in the flash
|
|
*
|
|
* @param bank the bank number to select
|
|
* @param boardBase base address of the IDE board
|
|
*/
|
|
void bankSelect(UBYTE bank, struct ideBoard *board) {
|
|
UBYTE *bankReg = board->cd->cd_BoardAddr + BANK_SEL_REG;
|
|
UBYTE regbits = *bankReg;
|
|
// Preserve the other bits
|
|
regbits &= 0x3F;
|
|
regbits |= (bank << 6);
|
|
*bankReg = regbits;
|
|
}
|
|
|
|
|
|
/**
|
|
* writeBufToFlash()
|
|
*
|
|
* Write the buffer to the currently selected flash bank
|
|
*
|
|
* @param source pointer to the source data
|
|
* @param dest pointer to the flash base
|
|
* @param size number of bytes to write
|
|
* @returns true on success
|
|
*/
|
|
BOOL writeBufToFlash(struct ideBoard *board, UBYTE *source, UBYTE *dest, ULONG size) {
|
|
UBYTE *sourcePtr = NULL;
|
|
UBYTE *destPtr = NULL;
|
|
|
|
int progress = 0;
|
|
int lastProgress = 1;
|
|
|
|
fprintf(stdout,"Writing: ");
|
|
fflush(stdout);
|
|
|
|
for (int i=0; i<size; i++) {
|
|
|
|
progress = (i*100)/(size-1);
|
|
|
|
if (lastProgress != progress) {
|
|
fprintf(stdout,"\b\b\b\b%3d%%",progress);
|
|
fflush(stdout);
|
|
lastProgress = progress;
|
|
}
|
|
sourcePtr = ((void *)source + i);
|
|
flash_writeByte(i,*sourcePtr);
|
|
|
|
}
|
|
|
|
fprintf(stdout,"\n");
|
|
fflush(stdout);
|
|
|
|
fprintf(stdout,"Verifying: ");
|
|
for (int i=0; i<size; i++) {
|
|
|
|
progress = (i*100)/(size-1);
|
|
|
|
if (lastProgress != progress) {
|
|
fprintf(stdout,"\b\b\b\b%3d%%",progress);
|
|
fflush(stdout);
|
|
lastProgress = progress;
|
|
}
|
|
sourcePtr = ((void *)source + i);
|
|
destPtr = ((void *)dest + (i << 1));
|
|
if (*sourcePtr != *destPtr) {
|
|
printf("\nVerification failed at %06x - Expected %02X but read %02X\n",(int)destPtr,*sourcePtr,*destPtr);
|
|
return false;
|
|
}
|
|
}
|
|
fprintf(stdout,"\n");
|
|
fflush(stdout);
|
|
return true;
|
|
}
|