From 022aff73313dd72e09863231640af5cd13839640 Mon Sep 17 00:00:00 2001 From: Dimitris Panokostas Date: Mon, 6 Mar 2017 22:02:31 +0100 Subject: [PATCH] Updated hardfile code --- src/hardfile.cpp | 2158 ++++++++++++++++++++++--------- src/osdep/hardfile_amiberry.cpp | 25 + 2 files changed, 1537 insertions(+), 646 deletions(-) diff --git a/src/hardfile.cpp b/src/hardfile.cpp index 1c18ef5f..4febfa5a 100644 --- a/src/hardfile.cpp +++ b/src/hardfile.cpp @@ -1,11 +1,11 @@ - /* - * UAE - The Un*x Amiga Emulator - * - * Hardfile emulation - * - * Copyright 1995 Bernd Schmidt - * 2002 Toni Wilen (scsi emulation, 64-bit support) - */ +/* +* UAE - The Un*x Amiga Emulator +* +* Hardfile emulation +* +* Copyright 1995 Bernd Schmidt +* 2002 Toni Wilen (scsi emulation, 64-bit support) +*/ #include "sysconfig.h" #include "sysdeps.h" @@ -23,6 +23,8 @@ #include "native2amiga.h" #include "gui.h" #include "uae.h" +#include "scsi.h" +//#include "gayle.h" #include "execio.h" #include "zfile.h" @@ -49,59 +51,57 @@ #define scsi_log write_log #endif - #define MAX_ASYNC_REQUESTS 50 #define ASYNC_REQUEST_NONE 0 #define ASYNC_REQUEST_TEMP 1 #define ASYNC_REQUEST_CHANGEINT 10 struct hardfileprivdata { - volatile uaecptr d_request[MAX_ASYNC_REQUESTS]; - volatile int d_request_type[MAX_ASYNC_REQUESTS]; - volatile uae_u32 d_request_data[MAX_ASYNC_REQUESTS]; - smp_comm_pipe requests; - int thread_running; - uae_thread_id thread_id; - uae_sem_t sync_sem; - uaecptr base; - int changenum; - uaecptr changeint; + volatile uaecptr d_request[MAX_ASYNC_REQUESTS]; + volatile int d_request_type[MAX_ASYNC_REQUESTS]; + volatile uae_u32 d_request_data[MAX_ASYNC_REQUESTS]; + smp_comm_pipe requests; + int thread_running; + uae_sem_t sync_sem; + uaecptr base; + int changenum; + uaecptr changeint; }; #define HFD_VHD_DYNAMIC 3 #define HFD_VHD_FIXED 2 #define HFD_CHD 1 -STATIC_INLINE uae_u32 gl (uae_u8 *p) +STATIC_INLINE uae_u32 gl(uae_u8 *p) { return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0); } -static uae_sem_t change_sem = 0; +static uae_sem_t change_sem; static struct hardfileprivdata hardfpd[MAX_FILESYSTEM_UNITS]; static uae_u32 nscmd_cmd; -static void wl (uae_u8 *p, int v) +static void wl(uae_u8 *p, int v) { p[0] = v >> 24; p[1] = v >> 16; p[2] = v >> 8; p[3] = v; } -static void ww (uae_u8 *p, int v) +static void ww(uae_u8 *p, int v) { p[0] = v >> 8; p[1] = v; } -static int rl (uae_u8 *p) +static int rl(uae_u8 *p) { return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]); } -static void getchs2 (struct hardfiledata *hfd, int *cyl, int *cylsec, int *head, int *tracksec) +static void getchs2(struct hardfiledata *hfd, int *cyl, int *cylsec, int *head, int *tracksec) { unsigned int total = (unsigned int)(hfd->virtsize / 1024); int heads; @@ -140,15 +140,15 @@ static void getchs2 (struct hardfiledata *hfd, int *cyl, int *cylsec, int *head, *head = heads; } -static void getchsx (struct hardfiledata *hfd, int *cyl, int *cylsec, int *head, int *tracksec) +static void getchsx(struct hardfiledata *hfd, int *cyl, int *cylsec, int *head, int *tracksec) { - getchs2 (hfd, cyl, cylsec, head, tracksec); - hf_log (_T("CHS: %08X-%08X %d %d %d %d %d\n"), - (uae_u32)(hfd->virtsize >> 32),(uae_u32)hfd->virtsize, + getchs2(hfd, cyl, cylsec, head, tracksec); + hf_log(_T("CHS: %08X-%08X %d %d %d %d %d\n"), + (uae_u32)(hfd->virtsize >> 32), (uae_u32)hfd->virtsize, *cyl, *cylsec, *head, *tracksec); } -static void getchsgeometry2 (uae_u64 size, int *pcyl, int *phead, int *psectorspertrack, int mode) +static void getchsgeometry2(uae_u64 size, int *pcyl, int *phead, int *psectorspertrack, int mode) { int sptt[4]; int i, spt, head, cyl; @@ -160,7 +160,8 @@ static void getchsgeometry2 (uae_u64 size, int *pcyl, int *phead, int *psectorsp spt = 32; cyl = total / (head * spt); - } else { + } + else { sptt[0] = 63; sptt[1] = 127; @@ -169,12 +170,13 @@ static void getchsgeometry2 (uae_u64 size, int *pcyl, int *phead, int *psectorsp for (i = 0; sptt[i] >= 0; i++) { spt = sptt[i]; - for (head = 4; head <= 16;head++) { + for (head = 4; head <= 16; head++) { cyl = total / (head * spt); if (size <= 512 * 1024 * 1024) { if (cyl <= 1023) break; - } else { + } + else { if (cyl < 16383) break; if (cyl < 32767 && head >= 5) @@ -194,12 +196,12 @@ static void getchsgeometry2 (uae_u64 size, int *pcyl, int *phead, int *psectorsp *psectorspertrack = spt; } -void getchsgeometry (uae_u64 size, int *pcyl, int *phead, int *psectorspertrack) +void getchsgeometry(uae_u64 size, int *pcyl, int *phead, int *psectorspertrack) { - getchsgeometry2 (size, pcyl, phead, psectorspertrack, 0); + getchsgeometry2(size, pcyl, phead, psectorspertrack, 0); } -void getchsgeometry_hdf (struct hardfiledata *hfd, uae_u64 size, int *pcyl, int *phead, int *psectorspertrack) +void getchsgeometry_hdf(struct hardfiledata *hfd, uae_u64 size, int *pcyl, int *phead, int *psectorspertrack) { uae_u8 block[512]; int i; @@ -209,33 +211,33 @@ void getchsgeometry_hdf (struct hardfiledata *hfd, uae_u64 size, int *pcyl, int *phead = 1; *psectorspertrack = 32; } - memset (block, 0, sizeof block); + memset(block, 0, sizeof block); if (hfd) { - hdf_read (hfd, block, 0, 512); + hdf_read(hfd, block, 0, 512); if (block[0] == 'D' && block[1] == 'O' && block[2] == 'S') { int mode; for (mode = 0; mode < 2; mode++) { uae_u32 rootblock; uae_u32 chk = 0; - getchsgeometry2 (size, pcyl, phead, psectorspertrack, mode); + getchsgeometry2(size, pcyl, phead, psectorspertrack, mode); rootblock = (2 + ((*pcyl) * (*phead) * (*psectorspertrack) - 1)) / 2; - memset (block, 0, sizeof block); - hdf_read (hfd, block, (uae_u64)rootblock * 512, 512); + memset(block, 0, sizeof block); + hdf_read(hfd, block, (uae_u64)rootblock * 512, 512); for (i = 0; i < 512; i += 4) chk += (block[i] << 24) | (block[i + 1] << 16) | (block[i + 2] << 8) | (block[i + 3] << 0); if (!chk && block[0] == 0 && block[1] == 0 && block[2] == 0 && block[3] == 2 && - block[4] == 0 && block[5] == 0 && block[6] == 0 && block[7] == 0 && - block[8] == 0 && block[9] == 0 && block[10] == 0 && block[11] == 0 && + block[4] == 0 && block[5] == 0 && block[6] == 0 && block[7] == 0 && + block[8] == 0 && block[9] == 0 && block[10] == 0 && block[11] == 0 && block[508] == 0 && block[509] == 0 && block[510] == 0 && block[511] == 1) { - return; + return; } } } } - getchsgeometry2 (size, pcyl, phead, psectorspertrack, size <= minsize ? 1 : 2); + getchsgeometry2(size, pcyl, phead, psectorspertrack, size <= minsize ? 1 : 2); } -void getchspgeometry (uae_u64 total, int *pcyl, int *phead, int *psectorspertrack, bool idegeometry) +void getchspgeometry(uae_u64 total, int *pcyl, int *phead, int *psectorspertrack, bool idegeometry) { uae_u64 blocks = total / 512; @@ -252,16 +254,16 @@ void getchspgeometry (uae_u64 total, int *pcyl, int *phead, int *psectorspertrac *pcyl = blocks / ((*psectorspertrack) * (*phead)); return; } - getchsgeometry (total, pcyl, phead, psectorspertrack); + getchsgeometry(total, pcyl, phead, psectorspertrack); } -static void getchshd (struct hardfiledata *hfd, int *pcyl, int *phead, int *psectorspertrack) +static void getchshd(struct hardfiledata *hfd, int *pcyl, int *phead, int *psectorspertrack) { - getchspgeometry (hfd->virtsize, pcyl, phead, psectorspertrack, false); + getchspgeometry(hfd->virtsize, pcyl, phead, psectorspertrack, false); } -static void pl (uae_u8 *p, int off, uae_u32 v) +static void pl(uae_u8 *p, int off, uae_u32 v) { p += off * 4; p[0] = v >> 24; @@ -270,27 +272,27 @@ static void pl (uae_u8 *p, int off, uae_u32 v) p[3] = v >> 0; } -static void rdb_crc (uae_u8 *p) +static void rdb_crc(uae_u8 *p) { uae_u32 sum; int i, blocksize; - sum =0; - blocksize = rl (p + 1 * 4); + sum = 0; + blocksize = rl(p + 1 * 4); for (i = 0; i < blocksize; i++) - sum += rl (p + i * 4); + sum += rl(p + i * 4); sum = -sum; - pl (p, 2, sum); + pl(p, 2, sum); } -static void create_virtual_rdb (struct hardfiledata *hfd) +static void create_virtual_rdb(struct hardfiledata *hfd) { uae_u8 *rdb, *part, *denv; int cyl = hfd->ci.surfaces * hfd->ci.sectors; int cyls = 262144 / (cyl * 512); int size = cyl * cyls * 512; - rdb = xcalloc (uae_u8, size); + rdb = xcalloc(uae_u8, size); hfd->virtual_rdb = rdb; hfd->virtual_size = size; part = rdb + 512; @@ -334,10 +336,10 @@ static void create_virtual_rdb (struct hardfiledata *hfd) pl(rdb, 37, 0); // autopark pl(rdb, 38, 2); // highrdskblock pl(rdb, 39, -1); // res - ua_copy ((char*)rdb + 40 * 4, -1, hfd->vendor_id); - ua_copy ((char*)rdb + 42 * 4, -1, hfd->product_id); - ua_copy ((char*)rdb + 46 * 4, -1, _T("UAE")); - rdb_crc (rdb); + ua_copy((char*)rdb + 40 * 4, -1, hfd->vendor_id); + ua_copy((char*)rdb + 42 * 4, -1, hfd->product_id); + ua_copy((char*)rdb + 46 * 4, -1, _T("UAE")); + rdb_crc(rdb); pl(part, 0, 0x50415254); pl(part, 1, 64); @@ -348,8 +350,8 @@ static void create_virtual_rdb (struct hardfiledata *hfd) pl(part, 6, -1); pl(part, 7, -1); pl(part, 8, 0); // devflags - part[9 * 4] = _tcslen (hfd->device_name); - ua_copy ((char*)part + 9 * 4 + 1, -1, hfd->device_name); + part[9 * 4] = _tcslen(hfd->device_name); + ua_copy((char*)part + 9 * 4 + 1, -1, hfd->device_name); denv = part + 128; pl(denv, 0, 80); @@ -369,45 +371,47 @@ static void create_virtual_rdb (struct hardfiledata *hfd) pl(denv, 14, hfd->ci.mask); pl(denv, 15, hfd->ci.bootpri); pl(denv, 16, hfd->ci.dostype); - rdb_crc (part); + rdb_crc(part); hfd->virtsize += size; } -void hdf_hd_close (struct hd_hardfiledata *hfd) +void hdf_hd_close(struct hd_hardfiledata *hfd) { if (!hfd) return; - hdf_close (&hfd->hfd); + hdf_close(&hfd->hfd); } -int hdf_hd_open (struct hd_hardfiledata *hfd) +int hdf_hd_open(struct hd_hardfiledata *hfd) { struct uaedev_config_info *ci = &hfd->hfd.ci; - if (!hdf_open (&hfd->hfd)) + if (!hdf_open(&hfd->hfd)) return 0; if (ci->pcyls && ci->pheads && ci->psecs) { hfd->cyls = ci->pcyls; hfd->heads = ci->pheads; hfd->secspertrack = ci->psecs; - } else if (ci->highcyl && ci->surfaces && ci->sectors) { + } + else if (ci->highcyl && ci->surfaces && ci->sectors) { hfd->cyls = ci->highcyl; hfd->heads = ci->surfaces; hfd->secspertrack = ci->sectors; - } else { - getchshd (&hfd->hfd, &hfd->cyls, &hfd->heads, &hfd->secspertrack); + } + else { + getchshd(&hfd->hfd, &hfd->cyls, &hfd->heads, &hfd->secspertrack); } hfd->cyls_def = hfd->cyls; hfd->secspertrack_def = hfd->secspertrack; hfd->heads_def = hfd->heads; if (ci->surfaces && ci->sectors) { uae_u8 buf[512] = { 0 }; - hdf_read (&hfd->hfd, buf, 0, 512); - if (buf[0] != 0 && memcmp (buf, _T("RDSK"), 4)) { + hdf_read(&hfd->hfd, buf, 0, 512); + if (buf[0] != 0 && memcmp(buf, _T("RDSK"), 4)) { ci->highcyl = (hfd->hfd.virtsize / ci->blocksize) / (ci->sectors * ci->surfaces); - ci->dostype = rl (buf); - create_virtual_rdb (&hfd->hfd); + ci->dostype = rl(buf); + create_virtual_rdb(&hfd->hfd); while (ci->highcyl * ci->surfaces * ci->sectors > hfd->cyls_def * hfd->secspertrack_def * hfd->heads_def) { hfd->cyls_def++; } @@ -417,28 +421,45 @@ int hdf_hd_open (struct hd_hardfiledata *hfd) return 1; } -static int hdf_write2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len); -static int hdf_read2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len); +static uae_u32 vhd_checksum(uae_u8 *p, int offset) +{ + int i; + uae_u32 sum; -static void hdf_init_cache (struct hardfiledata *hfd) + sum = 0; + for (i = 0; i < 512; i++) { + if (offset >= 0 && i >= offset && i < offset + 4) + continue; + sum += p[i]; + } + return ~sum; +} + +static int hdf_write2(struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len); +static int hdf_read2(struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len); + +static void hdf_init_cache(struct hardfiledata *hfd) { } -static void hdf_flush_cache (struct hardfiledata *hdf) +static void hdf_flush_cache(struct hardfiledata *hdf) { } -static int hdf_cache_read (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) +static int hdf_cache_read(struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) { - return hdf_read2 (hfd, buffer, offset, len); + return hdf_read2(hfd, buffer, offset, len); } -static int hdf_cache_write (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) +static int hdf_cache_write(struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) { - return hdf_write2 (hfd, buffer, offset, len); + return hdf_write2(hfd, buffer, offset, len); } -int hdf_open (struct hardfiledata *hfd, const TCHAR *pname) +int hdf_open(struct hardfiledata *hfd, const TCHAR *pname) { + uae_u8 tmp[512], tmp2[512]; + uae_u32 v; + if ((!pname || pname[0] == 0) && hfd->ci.rootdir[0] == 0) return 0; hfd->adide = 0; @@ -448,40 +469,96 @@ int hdf_open (struct hardfiledata *hfd, const TCHAR *pname) pname = hfd->ci.rootdir; #ifdef WITH_CHD TCHAR nametmp[MAX_DPATH]; - _tcscpy (nametmp, pname); - TCHAR *ext = _tcsrchr (nametmp, '.'); - if (ext && !_tcsicmp (ext, _T(".chd"))) { - struct zfile *zf = zfile_fopen (nametmp, _T("rb")); + _tcscpy(nametmp, pname); + TCHAR *ext = _tcsrchr(nametmp, '.'); + if (ext && !_tcsicmp(ext, _T(".chd"))) { + struct zfile *zf = zfile_fopen(nametmp, _T("rb")); if (zf) { int err; chd_file *cf = new chd_file(); err = cf->open(zf, false, NULL); if (err != CHDERR_NONE) { - zfile_fclose (zf); + zfile_fclose(zf); goto nonvhd; } hfd->chd_handle = cf; hfd->ci.readonly = true; hfd->hfd_type = HFD_CHD; hfd->handle_valid = -1; - hfd->virtsize = cf->logical_bytes (); + hfd->virtsize = cf->logical_bytes(); goto nonvhd; } } #endif - if (!hdf_open_target (hfd, pname)) + if (!hdf_open_target(hfd, pname)) return 0; + if (hdf_read_target(hfd, tmp, 0, 512) != 512) + goto nonvhd; + v = gl(tmp + 8); // features + if ((v & 3) != 2) + goto nonvhd; + v = gl(tmp + 8 + 4); // version + if ((v >> 16) != 1) + goto nonvhd; + hfd->hfd_type = gl(tmp + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4); + if (hfd->hfd_type != HFD_VHD_FIXED && hfd->hfd_type != HFD_VHD_DYNAMIC) + goto nonvhd; + v = gl(tmp + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4); + if (v == 0) + goto nonvhd; + if (vhd_checksum(tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4) != v) + goto nonvhd; + if (hdf_read_target(hfd, tmp2, hfd->physsize - sizeof tmp2, 512) != 512) + goto end; + if (memcmp(tmp, tmp2, sizeof tmp)) + goto nonvhd; + hfd->vhd_footerblock = hfd->physsize - 512; + hfd->virtsize = (uae_u64)(gl(tmp + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8)) << 32; + hfd->virtsize |= gl(tmp + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 4); + if (hfd->hfd_type == HFD_VHD_DYNAMIC) { + uae_u32 size; + hfd->vhd_bamoffset = gl(tmp + 8 + 4 + 4 + 4); + if (hfd->vhd_bamoffset == 0 || hfd->vhd_bamoffset >= hfd->physsize) + goto end; + if (hdf_read_target(hfd, tmp, hfd->vhd_bamoffset, 512) != 512) + goto end; + v = gl(tmp + 8 + 8 + 8 + 4 + 4 + 4); + if (vhd_checksum(tmp, 8 + 8 + 8 + 4 + 4 + 4) != v) + goto end; + v = gl(tmp + 8 + 8 + 8); + if ((v >> 16) != 1) + goto end; + hfd->vhd_blocksize = gl(tmp + 8 + 8 + 8 + 4 + 4); + hfd->vhd_bamoffset = gl(tmp + 8 + 8 + 4); + hfd->vhd_bamsize = (((hfd->virtsize + hfd->vhd_blocksize - 1) / hfd->vhd_blocksize) * 4 + 511) & ~511; + size = hfd->vhd_bamoffset + hfd->vhd_bamsize; + hfd->vhd_header = xmalloc(uae_u8, size); + if (hdf_read_target(hfd, hfd->vhd_header, 0, size) != size) + goto end; + hfd->vhd_sectormap = xmalloc(uae_u8, 512); + hfd->vhd_sectormapblock = -1; + hfd->vhd_bitmapsize = ((hfd->vhd_blocksize / (8 * 512)) + 511) & ~511; + } + write_log(_T("HDF is VHD %s image, virtual size=%lldK\n"), + hfd->hfd_type == HFD_VHD_FIXED ? _T("fixed") : _T("dynamic"), + hfd->virtsize / 1024); + hdf_init_cache(hfd); return 1; +nonvhd: + return 1; +end: + hdf_close_target(hfd); + return 0; } -int hdf_open (struct hardfiledata *hfd) +int hdf_open(struct hardfiledata *hfd) { - return hdf_open (hfd, NULL); + return hdf_open(hfd, NULL); } -void hdf_close (struct hardfiledata *hfd) +void hdf_close(struct hardfiledata *hfd) { - hdf_flush_cache (hfd); - hdf_close_target (hfd); + hdf_flush_cache(hfd); + hdf_close_target(hfd); #ifdef WITH_CHD if (hfd->chd_handle) { chd_file *cf = (chd_file*)hfd->chd_handle; @@ -490,38 +567,344 @@ void hdf_close (struct hardfiledata *hfd) } #endif hfd->hfd_type = 0; + xfree(hfd->vhd_header); + hfd->vhd_header = NULL; + xfree(hfd->vhd_sectormap); + hfd->vhd_sectormap = NULL; } -static int hdf_read2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) +int hdf_dup(struct hardfiledata *dhfd, const struct hardfiledata *shfd) { + return hdf_dup_target(dhfd, shfd); +} + +extern int get_guid_target(uae_u8 *out); + +static uae_u64 vhd_read(struct hardfiledata *hfd, void *v, uae_u64 offset, uae_u64 len) +{ + uae_u64 read; + uae_u8 *dataptr = (uae_u8*)v; + + //write_log (_T("%08x %08x\n"), (uae_u32)offset, (uae_u32)len); + read = 0; + if (offset & 511) + return read; + if (len & 511) + return read; + while (len > 0) { + uae_u32 bamoffset = (offset / hfd->vhd_blocksize) * 4 + hfd->vhd_bamoffset; + uae_u32 sectoroffset = gl(hfd->vhd_header + bamoffset); + if (sectoroffset == 0xffffffff) { + memset(dataptr, 0, 512); + read += 512; + } + else { + int bitmapoffsetbits; + int bitmapoffsetbytes; + uae_u64 sectormapblock; + + bitmapoffsetbits = (offset / 512) % (hfd->vhd_blocksize / 512); + bitmapoffsetbytes = bitmapoffsetbits / 8; + sectormapblock = sectoroffset * (uae_u64)512 + (bitmapoffsetbytes & ~511); + if (hfd->vhd_sectormapblock != sectormapblock) { + // read sector bitmap + //write_log (_T("BM %08x\n"), sectormapblock); + if (hdf_read_target(hfd, hfd->vhd_sectormap, sectormapblock, 512) != 512) { + write_log(_T("vhd_read: bitmap read error\n")); + return read; + } + hfd->vhd_sectormapblock = sectormapblock; + } + // block allocated in bitmap? + if (hfd->vhd_sectormap[bitmapoffsetbytes & 511] & (1 << (7 - (bitmapoffsetbits & 7)))) { + // read data block + uae_u64 block = sectoroffset * (uae_u64)512 + hfd->vhd_bitmapsize + bitmapoffsetbits * 512; + //write_log (_T("DB %08x\n"), block); + if (hdf_read_target(hfd, dataptr, block, 512) != 512) { + write_log(_T("vhd_read: data read error\n")); + return read; + } + } + else { + memset(dataptr, 0, 512); + } + read += 512; + } + len -= 512; + dataptr += 512; + offset += 512; + } + return read; +} + +static int vhd_write_enlarge(struct hardfiledata *hfd, uae_u32 bamoffset) +{ + uae_u8 *buf, *p; + int len; + uae_u32 block; + int v; + + len = hfd->vhd_blocksize + hfd->vhd_bitmapsize + 512; + buf = xcalloc(uae_u8, len); + if (!hdf_resize_target(hfd, hfd->physsize + len - 512)) { + write_log(_T("vhd_enlarge: failure\n")); + return 0; + } + // add footer (same as 512 byte header) + memcpy(buf + len - 512, hfd->vhd_header, 512); + v = hdf_write_target(hfd, buf, hfd->vhd_footerblock, len); + xfree(buf); + if (v != len) { + write_log(_T("vhd_enlarge: footer write error\n")); + return 0; + } + // write new offset to BAM + p = hfd->vhd_header + bamoffset; + block = hfd->vhd_footerblock / 512; + p[0] = block >> 24; + p[1] = block >> 16; + p[2] = block >> 8; + p[3] = block >> 0; + // write to disk + if (hdf_write_target(hfd, hfd->vhd_header + hfd->vhd_bamoffset, hfd->vhd_bamoffset, hfd->vhd_bamsize) != hfd->vhd_bamsize) { + write_log(_T("vhd_enlarge: bam write error\n")); + return 0; + } + hfd->vhd_footerblock += len - 512; + return 1; +} + +static uae_u64 vhd_write(struct hardfiledata *hfd, void *v, uae_u64 offset, uae_u64 len) +{ + uae_u64 written; + uae_u8 *dataptr = (uae_u8*)v; + + //write_log (_T("%08x %08x\n"), (uae_u32)offset, (uae_u32)len); + written = 0; + if (offset & 511) + return written; + if (len & 511) + return written; + while (len > 0) { + uae_u32 bamoffset = (offset / hfd->vhd_blocksize) * 4 + hfd->vhd_bamoffset; + uae_u32 sectoroffset = gl(hfd->vhd_header + bamoffset); + if (sectoroffset == 0xffffffff) { + if (!vhd_write_enlarge(hfd, bamoffset)) + return written; + continue; + } + else { + int bitmapoffsetbits; + int bitmapoffsetbytes; + + bitmapoffsetbits = (offset / 512) % (hfd->vhd_blocksize / 512); + bitmapoffsetbytes = bitmapoffsetbits / 8; + uae_u64 sectormapblock = sectoroffset * (uae_u64)512 + (bitmapoffsetbytes & ~511); + if (hfd->vhd_sectormapblock != sectormapblock) { + // read sector bitmap + if (hdf_read_target(hfd, hfd->vhd_sectormap, sectormapblock, 512) != 512) { + write_log(_T("vhd_write: bitmap read error\n")); + return written; + } + hfd->vhd_sectormapblock = sectormapblock; + } + // write data + if (hdf_write_target(hfd, dataptr, sectoroffset * (uae_u64)512 + hfd->vhd_bitmapsize + bitmapoffsetbits * 512, 512) != 512) { + write_log(_T("vhd_write: data write error\n")); + return written; + } + // block already allocated in bitmap? + if (!(hfd->vhd_sectormap[bitmapoffsetbytes & 511] & (1 << (7 - (bitmapoffsetbits & 7))))) { + // no, we need to mark it allocated and write the modified bitmap back to the disk + hfd->vhd_sectormap[bitmapoffsetbytes & 511] |= (1 << (7 - (bitmapoffsetbits & 7))); + if (hdf_write_target(hfd, hfd->vhd_sectormap, sectormapblock, 512) != 512) { + write_log(_T("vhd_write: bam write error\n")); + return written; + } + } + written += 512; + } + len -= 512; + dataptr += 512; + offset += 512; + } + return written; +} + + +int vhd_create(const TCHAR *name, uae_u64 size, uae_u32 dostype) +{ + struct hardfiledata hfd; + struct zfile *zf; + uae_u8 *b; + int cyl, cylsec, head, tracksec; + uae_u32 crc, blocksize, batsize, batentrysize; + int ret, i; + time_t tm; + + if (size >= (uae_u64)10 * 1024 * 1024 * 1024) + blocksize = 2 * 1024 * 1024; + else + blocksize = 512 * 1024; + batsize = (size + blocksize - 1) / blocksize; + batentrysize = batsize; + batsize *= 4; + batsize += 511; + batsize &= ~511; + ret = 0; + b = NULL; + zf = zfile_fopen(name, _T("wb"), 0); + if (!zf) + goto end; + b = xcalloc(uae_u8, 512 + 1024 + batsize + 512); + if (zfile_fwrite(b, 512 + 1024 + batsize + 512, 1, zf) != 1) + goto end; + + memset(&hfd, 0, sizeof hfd); + hfd.virtsize = hfd.physsize = size; + hfd.ci.blocksize = 512; + strcpy((char*)b, "conectix"); // cookie + b[0x0b] = 2; // features + b[0x0d] = 1; // version + b[0x10 + 6] = 2; // data offset + // time stamp + tm = time(NULL) - 946684800; + b[0x18] = tm >> 24; + b[0x19] = tm >> 16; + b[0x1a] = tm >> 8; + b[0x1b] = tm >> 0; + strcpy((char*)b + 0x1c, "vpc "); // creator application + b[0x21] = 5; // creator version + strcpy((char*)b + 0x24, "Wi2k"); // creator host os + // original and current size + b[0x28] = b[0x30] = size >> 56; + b[0x29] = b[0x31] = size >> 48; + b[0x2a] = b[0x32] = size >> 40; + b[0x2b] = b[0x33] = size >> 32; + b[0x2c] = b[0x34] = size >> 24; + b[0x2d] = b[0x35] = size >> 16; + b[0x2e] = b[0x36] = size >> 8; + b[0x2f] = b[0x37] = size >> 0; + getchs2(&hfd, &cyl, &cylsec, &head, &tracksec); + // cylinders + b[0x38] = cyl >> 8; + b[0x39] = cyl; + // heads + b[0x3a] = head; + // sectors per track + b[0x3b] = tracksec; + // disk type + b[0x3c + 3] = HFD_VHD_DYNAMIC; + get_guid_target(b + 0x44); + crc = vhd_checksum(b, -1); + b[0x40] = crc >> 24; + b[0x41] = crc >> 16; + b[0x42] = crc >> 8; + b[0x43] = crc >> 0; + + // write header + zfile_fseek(zf, 0, SEEK_SET); + zfile_fwrite(b, 512, 1, zf); + // write footer + zfile_fseek(zf, 512 + 1024 + batsize, SEEK_SET); + zfile_fwrite(b, 512, 1, zf); + + // dynamic disk header + memset(b, 0, 1024); + // cookie + strcpy((char*)b, "cxsparse"); + // data offset + for (i = 0; i < 8; i++) + b[0x08 + i] = 0xff; + // table offset (bat) + b[0x10 + 6] = 0x06; + // version + b[0x19] = 1; + // max table entries + b[0x1c] = batentrysize >> 24; + b[0x1d] = batentrysize >> 16; + b[0x1e] = batentrysize >> 8; + b[0x1f] = batentrysize >> 0; + b[0x20] = blocksize >> 24; + b[0x21] = blocksize >> 16; + b[0x22] = blocksize >> 8; + b[0x23] = blocksize >> 0; + crc = vhd_checksum(b, -1); + b[0x24] = crc >> 24; + b[0x25] = crc >> 16; + b[0x26] = crc >> 8; + b[0x27] = crc >> 0; + + // write dynamic header + zfile_fseek(zf, 512, SEEK_SET); + zfile_fwrite(b, 1024, 1, zf); + + // bat + memset(b, 0, batsize); + memset(b, 0xff, batentrysize * 4); + zfile_fwrite(b, batsize, 1, zf); + + zfile_fclose(zf); + zf = NULL; + + if (dostype) { + uae_u8 bootblock[512] = { 0 }; + bootblock[0] = dostype >> 24; + bootblock[1] = dostype >> 16; + bootblock[2] = dostype >> 8; + bootblock[3] = dostype >> 0; + if (hdf_open(&hfd, name)) { + vhd_write(&hfd, bootblock, 0, 512); + hdf_close(&hfd); + } + } + + ret = 1; + +end: + xfree(b); + zfile_fclose(zf); + return ret; +} + +static int hdf_read2(struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) +{ + if (hfd->hfd_type == HFD_VHD_DYNAMIC) + return vhd_read(hfd, buffer, offset, len); + else if (hfd->hfd_type == HFD_VHD_FIXED) + return hdf_read_target(hfd, buffer, offset + 512, len); #ifdef WITH_CHD - if (hfd->hfd_type == HFD_CHD) { + else if (hfd->hfd_type == HFD_CHD) { chd_file *cf = (chd_file*)hfd->chd_handle; if (cf->read_bytes(offset, buffer, len) == CHDERR_NONE) return len; return 0; } - else #endif - return hdf_read_target (hfd, buffer, offset, len); + else + return hdf_read_target(hfd, buffer, offset, len); } -static int hdf_write2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) +static int hdf_write2(struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) { + if (hfd->hfd_type == HFD_VHD_DYNAMIC) + return vhd_write(hfd, buffer, offset, len); + else if (hfd->hfd_type == HFD_VHD_FIXED) + return hdf_write_target(hfd, buffer, offset + 512, len); #ifdef WITH_CHD - if (hfd->hfd_type == HFD_CHD) + else if (hfd->hfd_type == HFD_CHD) return 0; - else #endif - return hdf_write_target (hfd, buffer, offset, len); + else + return hdf_write_target(hfd, buffer, offset, len); } -static void adide_decode (void *v, int len) +static void adide_decode(void *v, int len) { int i; uae_u8 *buffer = (uae_u8*)v; for (i = 0; i < len; i += 2) { - uae_u8 *b = buffer + i; + uae_u8 *b = buffer + i; uae_u16 w = (b[0] << 8) | (b[1] << 0); uae_u16 o = 0; @@ -569,12 +952,12 @@ static void adide_decode (void *v, int len) b[1] = o >> 0; } } -static void adide_encode (void *v, int len) +static void adide_encode(void *v, int len) { int i; uae_u8 *buffer = (uae_u8*)v; for (i = 0; i < len; i += 2) { - uae_u8 *b = buffer + i; + uae_u8 *b = buffer + i; uae_u16 w = (b[0] << 8) | (b[1] << 0); uae_u16 o = 0; @@ -623,7 +1006,7 @@ static void adide_encode (void *v, int len) } } -static void hdf_byteswap (void *v, int len) +static void hdf_byteswap(void *v, int len) { int i; uae_u8 *b = (uae_u8*)v; @@ -635,96 +1018,99 @@ static void hdf_byteswap (void *v, int len) } } -int hdf_read_rdb (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) +int hdf_read_rdb(struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) { int v; - v = hdf_read (hfd, buffer, offset, len); - if (v > 0 && offset < 16 * 512 && !hfd->byteswap && !hfd->adide) { + v = hdf_read(hfd, buffer, offset, len); + if (v > 0 && offset < 16 * 512 && !hfd->byteswap && !hfd->adide) { uae_u8 *buf = (uae_u8*)buffer; bool changed = false; if (buf[0] == 0x39 && buf[1] == 0x10 && buf[2] == 0xd3 && buf[3] == 0x12) { // AdIDE encoded "CPRM" hfd->adide = 1; changed = true; - write_log (_T("HDF: adide scrambling detected\n")); - } else if (!memcmp (buf, "DRKS", 4)) { + write_log(_T("HDF: adide scrambling detected\n")); + } + else if (!memcmp(buf, "DRKS", 4)) { hfd->byteswap = 1; changed = true; - write_log (_T("HDF: byteswapped RDB detected\n")); + write_log(_T("HDF: byteswapped RDB detected\n")); } if (changed) - v = hdf_read (hfd, buffer, offset, len); + v = hdf_read(hfd, buffer, offset, len); } return v; } -int hdf_read (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) +int hdf_read(struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) { int v; - hf_log3 (_T("cmd_read: %p %04x-%08x (%d) %08x (%d)\n"), + hf_log3(_T("cmd_read: %p %04x-%08x (%d) %08x (%d)\n"), buffer, (uae_u32)(offset >> 32), (uae_u32)offset, (uae_u32)(offset / hfd->ci.blocksize), (uae_u32)len, (uae_u32)(len / hfd->ci.blocksize)); if (!hfd->adide) { - v = hdf_cache_read (hfd, buffer, offset, len); - } else { + v = hdf_cache_read(hfd, buffer, offset, len); + } + else { offset += 512; - v = hdf_cache_read (hfd, buffer, offset, len); - adide_decode (buffer, len); + v = hdf_cache_read(hfd, buffer, offset, len); + adide_decode(buffer, len); } if (hfd->byteswap) - hdf_byteswap (buffer, len); + hdf_byteswap(buffer, len); return v; } -int hdf_write (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) +int hdf_write(struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) { int v; - hf_log3 (_T("cmd_write: %p %04x-%08x (%d) %08x (%d)\n"), + hf_log3(_T("cmd_write: %p %04x-%08x (%d) %08x (%d)\n"), buffer, (uae_u32)(offset >> 32), (uae_u32)offset, (uae_u32)(offset / hfd->ci.blocksize), (uae_u32)len, (uae_u32)(len / hfd->ci.blocksize)); if (hfd->byteswap) - hdf_byteswap (buffer, len); + hdf_byteswap(buffer, len); if (!hfd->adide) { - v = hdf_cache_write (hfd, buffer, offset, len); - } else { + v = hdf_cache_write(hfd, buffer, offset, len); + } + else { offset += 512; - adide_encode (buffer, len); - v = hdf_cache_write (hfd, buffer, offset, len); - adide_decode (buffer, len); + adide_encode(buffer, len); + v = hdf_cache_write(hfd, buffer, offset, len); + adide_decode(buffer, len); } if (hfd->byteswap) - hdf_byteswap (buffer, len); + hdf_byteswap(buffer, len); return v; } -static uae_u64 cmd_readx (struct hardfiledata *hfd, uae_u8 *dataptr, uae_u64 offset, uae_u64 len) +static uae_u64 cmd_readx(struct hardfiledata *hfd, uae_u8 *dataptr, uae_u64 offset, uae_u64 len) { - gui_flicker_led (LED_HD, 1); - return hdf_read (hfd, dataptr, offset, len); + gui_flicker_led(LED_HD, hfd->unitnum, 1); + return hdf_read(hfd, dataptr, offset, len); } -static uae_u64 cmd_read (struct hardfiledata *hfd, uaecptr dataptr, uae_u64 offset, uae_u64 len) +static uae_u64 cmd_read(struct hardfiledata *hfd, uaecptr dataptr, uae_u64 offset, uae_u64 len) { - addrbank *bank_data = &get_mem_bank (dataptr); - if (!len || !bank_data || !bank_data->check (dataptr, len)) - return 0; - return cmd_readx (hfd, bank_data->xlateaddr (dataptr), offset, len); + addrbank *bank_data = &get_mem_bank(dataptr); + if (!len || !bank_data || !bank_data->check(dataptr, len)) + return 0; + return cmd_readx(hfd, bank_data->xlateaddr(dataptr), offset, len); } -static uae_u64 cmd_writex (struct hardfiledata *hfd, uae_u8 *dataptr, uae_u64 offset, uae_u64 len) +static uae_u64 cmd_writex(struct hardfiledata *hfd, uae_u8 *dataptr, uae_u64 offset, uae_u64 len) { - gui_flicker_led (LED_HD, 1); - return hdf_write (hfd, dataptr, offset, len); + gui_flicker_led(LED_HD, hfd->unitnum, 2); + return hdf_write(hfd, dataptr, offset, len); } -static uae_u64 cmd_write (struct hardfiledata *hfd, uaecptr dataptr, uae_u64 offset, uae_u64 len) +static uae_u64 cmd_write(struct hardfiledata *hfd, uaecptr dataptr, uae_u64 offset, uae_u64 len) { - addrbank *bank_data = &get_mem_bank (dataptr); - if (!len || !bank_data || !bank_data->check (dataptr, len)) - return 0; - return cmd_writex (hfd, bank_data->xlateaddr (dataptr), offset, len); + addrbank *bank_data = &get_mem_bank(dataptr); + if (!len || !bank_data || !bank_data->check(dataptr, len)) + return 0; + return cmd_writex(hfd, bank_data->xlateaddr(dataptr), offset, len); } -static int checkbounds (struct hardfiledata *hfd, uae_u64 offset, uae_u64 len) +static int checkbounds(struct hardfiledata *hfd, uae_u64 offset, uae_u64 len) { if (offset >= hfd->virtsize) return 0; @@ -733,656 +1119,1136 @@ static int checkbounds (struct hardfiledata *hfd, uae_u64 offset, uae_u64 len) return 1; } -static int nodisk (struct hardfiledata *hfd) +static int nodisk(struct hardfiledata *hfd) { - if (hfd->drive_empty) - return 1; - return 0; + if (hfd->drive_empty) + return 1; + return 0; } -void hardfile_send_disk_change (struct hardfiledata *hfd, bool insert) +int scsi_hd_emulate(struct hardfiledata *hfd, struct hd_hardfiledata *hdhfd, uae_u8 *cmdbuf, int scsi_cmd_len, + uae_u8 *scsi_data, int *data_len, uae_u8 *r, int *reply_len, uae_u8 *s, int *sense_len) +{ + uae_u64 len, offset; + int lr = 0, ls = 0; + int scsi_len = -1; + int status = 0; + int i, lun; + char *ss; + + *reply_len = *sense_len = 0; + lun = cmdbuf[1] >> 5; + if (cmdbuf[0] != 0x03 && cmdbuf[0] != 0x12 && lun) { + status = 2; /* CHECK CONDITION */ + s[0] = 0x70; + s[2] = 5; /* ILLEGAL REQUEST */ + s[12] = 0x25; /* INVALID LUN */ + ls = 0x12; + goto err; + } + switch (cmdbuf[0]) + { + case 0x00: /* TEST UNIT READY */ + if (nodisk(hfd)) + goto nodisk; + scsi_len = 0; + break; + case 0x03: /* REQUEST SENSE */ + scsi_len = cmdbuf[4] > MAX_SCSI_SENSE ? MAX_SCSI_SENSE : cmdbuf[4]; + memcpy(r, hfd->scsi_sense, scsi_len); + memset(hfd->scsi_sense, 0, MAX_SCSI_SENSE); + break; + case 0x08: /* READ (6) */ + if (nodisk(hfd)) + goto nodisk; + offset = ((cmdbuf[1] & 31) << 16) | (cmdbuf[2] << 8) | cmdbuf[3]; + offset *= hfd->ci.blocksize; + len = cmdbuf[4]; + if (!len) + len = 256; + len *= hfd->ci.blocksize; + if (!checkbounds(hfd, offset, len)) + goto outofbounds; + scsi_len = (uae_u32)cmd_readx(hfd, scsi_data, offset, len); + break; + case 0x0a: /* WRITE (6) */ + if (nodisk(hfd)) + goto nodisk; + if (hfd->ci.readonly || hfd->dangerous) + goto readprot; + offset = ((cmdbuf[1] & 31) << 16) | (cmdbuf[2] << 8) | cmdbuf[3]; + offset *= hfd->ci.blocksize; + len = cmdbuf[4]; + if (!len) + len = 256; + len *= hfd->ci.blocksize; + if (!checkbounds(hfd, offset, len)) + goto outofbounds; + scsi_len = (uae_u32)cmd_writex(hfd, scsi_data, offset, len); + break; + case 0x12: /* INQUIRY */ + { + if ((cmdbuf[1] & 1) || cmdbuf[2] != 0) + goto err; + int alen = (cmdbuf[3] << 8) | cmdbuf[4]; + if (lun != 0) { + r[0] = 0x7f; + } + else { + r[0] = 0; + if (hfd->drive_empty) { + r[1] |= 0x80; // removable.. + r[0] |= 0x20; // not present + } + } + r[2] = 2; /* supports SCSI-2 */ + r[3] = 2; /* response data format */ + r[4] = 32; /* additional length */ + r[7] = 0x20; /* 16 bit bus */ + scsi_len = lr = alen < 36 ? alen : 36; + if (hdhfd) { + r[2] = hdhfd->ansi_version; + r[3] = hdhfd->ansi_version >= 2 ? 2 : 0; + } + ss = ua(hfd->vendor_id); + i = 0; /* vendor id */ + while (i < 8 && ss[i]) { + r[8 + i] = ss[i]; + i++; + } + while (i < 8) { + r[8 + i] = 32; + i++; + } + xfree(ss); + ss = ua(hfd->product_id); + i = 0; /* product id */ + while (i < 16 && ss[i]) { + r[16 + i] = ss[i]; + i++; + } + while (i < 16) { + r[16 + i] = 32; + i++; + } + xfree(ss); + ss = ua(hfd->product_rev); + i = 0; /* product revision */ + while (i < 4 && ss[i]) { + r[32 + i] = ss[i]; + i++; + } + while (i < 4) { + r[32 + i] = 32; + i++; + } + xfree(ss); + } + break; + case 0x1a: /* MODE SENSE(6) */ + { + uae_u8 *p; + int pc = cmdbuf[2] >> 6; + int pcode = cmdbuf[2] & 0x3f; + int dbd = cmdbuf[1] & 8; + int alen = cmdbuf[4]; + int cyl, cylsec, head, tracksec; + if (nodisk(hfd)) + goto nodisk; + if (hdhfd) { + cyl = hdhfd->cyls; + head = hdhfd->heads; + tracksec = hdhfd->secspertrack; + cylsec = 0; + } + else { + getchsx(hfd, &cyl, &cylsec, &head, &tracksec); + } + //write_log (_T("MODE SENSE PC=%d CODE=%d DBD=%d\n"), pc, pcode, dbd); + p = r; + p[0] = 4 - 1; + p[1] = 0; + p[2] = (hfd->ci.readonly || hfd->dangerous) ? 0x80 : 0x00; + p[3] = 0; + p += 4; + if (!dbd) { + if (alen >= r[0] + 1 + 8) { + uae_u32 blocks = (uae_u32)(hfd->virtsize / hfd->ci.blocksize); + p[-1] = 8; + wl(p + 0, blocks); + wl(p + 4, hfd->ci.blocksize); + p += 8; + } + } + if (pcode == 0) { + if (alen >= r[0] + 1 + r[3] + 4) { + p[0] = 0; + p[1] = 3; + p[2] = 0x20; + p[3] = 0; + r[0] += p[1]; + } + } + else if (pcode == 3) { + // format parameters + if (alen >= r[0] + 1 + r[3] + 24) { + p[0] = 3; + p[1] = 24; + p[3] = 1; + p[10] = tracksec >> 8; + p[11] = tracksec; + p[12] = hfd->ci.blocksize >> 8; + p[13] = hfd->ci.blocksize; + p[15] = 1; // interleave + p[20] = 0x80; + r[0] += p[1]; + } + } + else if (pcode == 4) { + // rigid drive geometry + if (alen >= r[0] + 1 + r[3] + 16) { + p[0] = 4; + wl(p + 1, cyl); + p[1] = 24; + p[5] = head; + wl(p + 13, cyl); + ww(p + 20, 5400); + r[0] += p[1]; + } + } + else { + goto err; + } + r[0] += r[3]; + scsi_len = lr = r[0] + 1; + if (scsi_len > alen) + scsi_len = alen; + break; + } + break; + case 0x1d: /* SEND DIAGNOSTICS */ + break; + case 0x25: /* READ_CAPACITY */ + { + int pmi = cmdbuf[8] & 1; + uae_u32 lba = (cmdbuf[2] << 24) | (cmdbuf[3] << 16) | (cmdbuf[4] << 8) | cmdbuf[5]; + uae_u32 blocks; + int cyl, cylsec, head, tracksec; + if (nodisk(hfd)) + goto nodisk; + blocks = (uae_u32)(hfd->virtsize / hfd->ci.blocksize - 1); + if (hdhfd) { + cyl = hdhfd->cyls; + head = hdhfd->heads; + tracksec = hdhfd->secspertrack; + cylsec = 0; + } + else { + getchsx(hfd, &cyl, &cylsec, &head, &tracksec); + } + if (pmi == 0 && lba != 0) + goto errreq; + if (pmi) { + lba += tracksec * head; + lba /= tracksec * head; + lba *= tracksec * head; + if (lba > blocks) + lba = blocks; + blocks = lba; + } + wl(r, blocks); + wl(r + 4, hfd->ci.blocksize); + scsi_len = lr = 8; + } + break; + case 0x28: /* READ (10) */ + if (nodisk(hfd)) + goto nodisk; + offset = rl(cmdbuf + 2); + offset *= hfd->ci.blocksize; + len = rl(cmdbuf + 7 - 2) & 0xffff; + len *= hfd->ci.blocksize; + if (!checkbounds(hfd, offset, len)) + goto outofbounds; + scsi_len = (uae_u32)cmd_readx(hfd, scsi_data, offset, len); + break; + case 0x2a: /* WRITE (10) */ + if (nodisk(hfd)) + goto nodisk; + if (hfd->ci.readonly || hfd->dangerous) + goto readprot; + offset = rl(cmdbuf + 2); + offset *= hfd->ci.blocksize; + len = rl(cmdbuf + 7 - 2) & 0xffff; + len *= hfd->ci.blocksize; + if (!checkbounds(hfd, offset, len)) + goto outofbounds; + scsi_len = (uae_u32)cmd_writex(hfd, scsi_data, offset, len); + break; + case 0x2f: /* VERIFY (10) */ + { + int bytchk = cmdbuf[1] & 2; + if (nodisk(hfd)) + goto nodisk; + if (bytchk) { + offset = rl(cmdbuf + 2); + offset *= hfd->ci.blocksize; + len = rl(cmdbuf + 7 - 2) & 0xffff; + len *= hfd->ci.blocksize; + uae_u8 *vb = xmalloc(uae_u8, hfd->ci.blocksize); + if (checkbounds(hfd, offset, len)) { + while (len > 0) { + int readlen = cmd_readx(hfd, vb, offset, hfd->ci.blocksize); + if (readlen != hfd->ci.blocksize || memcmp(vb, scsi_data, hfd->ci.blocksize)) { + xfree(vb); + goto miscompare; + } + scsi_data += hfd->ci.blocksize; + offset += hfd->ci.blocksize; + len -= hfd->ci.blocksize; + } + } + xfree(vb); + } + scsi_len = 0; + } + break; + case 0x35: /* SYNCRONIZE CACHE (10) */ + if (nodisk(hfd)) + goto nodisk; + scsi_len = 0; + break; + case 0xa8: /* READ (12) */ + if (nodisk(hfd)) + goto nodisk; + offset = rl(cmdbuf + 2); + offset *= hfd->ci.blocksize; + len = rl(cmdbuf + 6); + len *= hfd->ci.blocksize; + if (!checkbounds(hfd, offset, len)) + goto outofbounds; + scsi_len = (uae_u32)cmd_readx(hfd, scsi_data, offset, len); + break; + case 0xaa: /* WRITE (12) */ + if (nodisk(hfd)) + goto nodisk; + if (hfd->ci.readonly || hfd->dangerous) + goto readprot; + offset = rl(cmdbuf + 2); + offset *= hfd->ci.blocksize; + len = rl(cmdbuf + 6); + len *= hfd->ci.blocksize; + if (!checkbounds(hfd, offset, len)) + goto outofbounds; + scsi_len = (uae_u32)cmd_writex(hfd, scsi_data, offset, len); + break; + case 0x37: /* READ DEFECT DATA */ + if (nodisk(hfd)) + goto nodisk; + status = 2; /* CHECK CONDITION */ + s[0] = 0x70; + s[2] = 0; /* NO SENSE */ + s[12] = 0x1c; /* DEFECT LIST NOT FOUND */ + ls = 0x12; + break; + case 0x1b: /* START/STOP UNIT */ + scsi_len = 0; + break; + readprot: + status = 2; /* CHECK CONDITION */ + s[0] = 0x70; + s[2] = 7; /* DATA PROTECT */ + s[12] = 0x27; /* WRITE PROTECTED */ + ls = 0x12; + break; + nodisk: + status = 2; /* CHECK CONDITION */ + s[0] = 0x70; + s[2] = 2; /* NOT READY */ + s[12] = 0x3A; /* MEDIUM NOT PRESENT */ + ls = 0x12; + break; + + default: + err: + write_log(_T("UAEHF: unsupported scsi command 0x%02X LUN=%d\n"), cmdbuf[0], lun); + errreq: + lr = -1; + status = 2; /* CHECK CONDITION */ + s[0] = 0x70; + s[2] = 5; /* ILLEGAL REQUEST */ + s[12] = 0x24; /* ILLEGAL FIELD IN CDB */ + ls = 0x12; + break; + outofbounds: + lr = -1; + status = 2; /* CHECK CONDITION */ + s[0] = 0x70; + s[2] = 5; /* ILLEGAL REQUEST */ + s[12] = 0x21; /* LOGICAL BLOCK OUT OF RANGE */ + ls = 0x12; + break; + miscompare: + lr = -1; + status = 2; /* CHECK CONDITION */ + s[0] = 0x70; + s[2] = 5; /* ILLEGAL REQUEST */ + s[12] = 0x1d; /* MISCOMPARE DURING VERIFY OPERATION */ + ls = 0x12; + break; + } + *data_len = scsi_len; + *reply_len = lr; + *sense_len = ls; + if (ls > 0) { + memset(hfd->scsi_sense, 0, MAX_SCSI_SENSE); + memcpy(hfd->scsi_sense, s, ls); + } + return status; +} + +static int handle_scsi(uaecptr request, struct hardfiledata *hfd) +{ + uae_u32 acmd = get_long(request + 40); + uaecptr scsi_data = get_long(acmd + 0); + int scsi_len = get_long(acmd + 4); + uaecptr scsi_cmd = get_long(acmd + 12); + uae_u16 scsi_cmd_len = get_word(acmd + 16); + uae_u8 scsi_flags = get_byte(acmd + 20); + uaecptr scsi_sense = get_long(acmd + 22); + uae_u16 scsi_sense_len = get_word(acmd + 26); + uae_u8 cmd = get_byte(scsi_cmd); + uae_u8 cmdbuf[256]; + int status, ret = 0, reply_len, sense_len; + uae_u32 i; + uae_u8 reply[256], sense[256]; + uae_u8 *scsi_data_ptr = NULL; + addrbank *bank_data = &get_mem_bank(scsi_data); + + if (bank_data && bank_data->check(scsi_data, scsi_len)) + scsi_data_ptr = bank_data->xlateaddr(scsi_data); + scsi_sense_len = (scsi_flags & 4) ? 4 : /* SCSIF_OLDAUTOSENSE */ + (scsi_flags & 2) ? scsi_sense_len : /* SCSIF_AUTOSENSE */ + 32; + status = 0; + memset(reply, 0, sizeof reply); + reply_len = 0; sense_len = 0; + scsi_log(_T("hdf scsiemu: cmd=%02X,%d flags=%02X sense=%p,%d data=%p,%d\n"), + cmd, scsi_cmd_len, scsi_flags, scsi_sense, scsi_sense_len, scsi_data, scsi_len); + for (i = 0; i < scsi_cmd_len; i++) { + cmdbuf[i] = get_byte(scsi_cmd + i); + scsi_log(_T("%02X%c"), get_byte(scsi_cmd + i), i < scsi_cmd_len - 1 ? '.' : ' '); + } + scsi_log(_T("\n")); + + status = scsi_hd_emulate(hfd, NULL, cmdbuf, scsi_cmd_len, scsi_data_ptr, &scsi_len, reply, &reply_len, sense, &sense_len); + + put_word(acmd + 18, status != 0 ? 0 : scsi_cmd_len); /* fake scsi_CmdActual */ + put_byte(acmd + 21, status); /* scsi_Status */ + if (reply_len > 0) { + scsi_log(_T("RD:")); + i = 0; + while (i < reply_len) { + if (i < 24) { + scsi_log(_T("%02X%c"), reply[i], i < reply_len - 1 ? '.' : ' '); + } + put_byte(scsi_data + i, reply[i]); + i++; + } + scsi_log(_T("\n")); + } + i = 0; + if (scsi_sense) { + while (i < sense_len && i < scsi_sense_len) { + put_byte(scsi_sense + i, sense[i]); + i++; + } + } + while (i < scsi_sense_len && scsi_sense) { + put_byte(scsi_sense + i, 0); + i++; + } + if (scsi_len < 0) { + put_long(acmd + 8, 0); /* scsi_Actual */ + ret = 20; + } + else { + put_long(acmd + 8, scsi_len); /* scsi_Actual */ + } + return ret; +} + + +void hardfile_send_disk_change(struct hardfiledata *hfd, bool insert) { int newstate = insert ? 0 : 1; - uae_sem_wait (&change_sem); + uae_sem_wait(&change_sem); hardfpd[hfd->unitnum].changenum++; - write_log (_T("uaehf.device:%d media status=%d changenum=%d\n"), hfd->unitnum, insert, hardfpd[hfd->unitnum].changenum); + write_log(_T("uaehf.device:%d media status=%d changenum=%d\n"), hfd->unitnum, insert, hardfpd[hfd->unitnum].changenum); hfd->drive_empty = newstate; int j = 0; while (j < MAX_ASYNC_REQUESTS) { if (hardfpd[hfd->unitnum].d_request_type[j] == ASYNC_REQUEST_CHANGEINT) { - uae_Cause (hardfpd[hfd->unitnum].d_request_data[j]); + uae_Cause(hardfpd[hfd->unitnum].d_request_data[j]); } j++; } if (hardfpd[hfd->unitnum].changeint) - uae_Cause (hardfpd[hfd->unitnum].changeint); - uae_sem_post (&change_sem); + uae_Cause(hardfpd[hfd->unitnum].changeint); + uae_sem_post(&change_sem); } -void hardfile_do_disk_change (struct uaedev_config_data *uci, bool insert) +void hardfile_do_disk_change(struct uaedev_config_data *uci, bool insert) { - int fsid = uci->configoffset; - struct hardfiledata *hfd; + int fsid = uci->configoffset; + struct hardfiledata *hfd; - hfd = get_hardfile_data (fsid); - if (!hfd) - return; - hardfile_send_disk_change (hfd, insert); + if (uci->ci.controller == HD_CONTROLLER_PCMCIA_SRAM) { + //gayle_modify_pcmcia_sram_unit(uci->ci.rootdir, uci->ci.readonly, insert); //TODO + return; + } + else if (uci->ci.controller == HD_CONTROLLER_PCMCIA_IDE) { + //gayle_modify_pcmcia_ide_unit(uci->ci.rootdir, uci->ci.readonly, insert); //TODO + return; + } + hfd = get_hardfile_data(fsid); + if (!hfd) + return; + hardfile_send_disk_change(hfd, insert); } -static int add_async_request (struct hardfileprivdata *hfpd, uaecptr request, int type, uae_u32 data) +static int add_async_request(struct hardfileprivdata *hfpd, uaecptr request, int type, uae_u32 data) { - int i; + int i; - i = 0; - while (i < MAX_ASYNC_REQUESTS) { - if (hfpd->d_request[i] == request) { - hfpd->d_request_type[i] = type; - hfpd->d_request_data[i] = data; - hf_log (_T("old async request %p (%d) added\n"), request, type); - return 0; - } - i++; - } - i = 0; - while (i < MAX_ASYNC_REQUESTS) { - if (hfpd->d_request[i] == 0) { - hfpd->d_request[i] = request; - hfpd->d_request_type[i] = type; - hfpd->d_request_data[i] = data; - hf_log (_T("async request %p (%d) added (total=%d)\n"), request, type, i); - return 0; - } - i++; - } - hf_log (_T("async request overflow %p!\n"), request); - return -1; + i = 0; + while (i < MAX_ASYNC_REQUESTS) { + if (hfpd->d_request[i] == request) { + hfpd->d_request_type[i] = type; + hfpd->d_request_data[i] = data; + hf_log(_T("old async request %p (%d) added\n"), request, type); + return 0; + } + i++; + } + i = 0; + while (i < MAX_ASYNC_REQUESTS) { + if (hfpd->d_request[i] == 0) { + hfpd->d_request[i] = request; + hfpd->d_request_type[i] = type; + hfpd->d_request_data[i] = data; + hf_log(_T("async request %p (%d) added (total=%d)\n"), request, type, i); + return 0; + } + i++; + } + hf_log(_T("async request overflow %p!\n"), request); + return -1; } -static int release_async_request (struct hardfileprivdata *hfpd, uaecptr request) +static int release_async_request(struct hardfileprivdata *hfpd, uaecptr request) { - int i = 0; + int i = 0; - while (i < MAX_ASYNC_REQUESTS) { - if (hfpd->d_request[i] == request) { - int type = hfpd->d_request_type[i]; - hfpd->d_request[i] = 0; - hfpd->d_request_data[i] = 0; - hfpd->d_request_type[i] = 0; - hf_log (_T("async request %p removed\n"), request); - return type; - } - i++; - } - hf_log (_T("tried to remove non-existing request %p\n"), request); - return -1; + while (i < MAX_ASYNC_REQUESTS) { + if (hfpd->d_request[i] == request) { + int type = hfpd->d_request_type[i]; + hfpd->d_request[i] = 0; + hfpd->d_request_data[i] = 0; + hfpd->d_request_type[i] = 0; + hf_log(_T("async request %p removed\n"), request); + return type; + } + i++; + } + hf_log(_T("tried to remove non-existing request %p\n"), request); + return -1; } -static void abort_async (struct hardfileprivdata *hfpd, uaecptr request, int errcode, int type) +static void abort_async(struct hardfileprivdata *hfpd, uaecptr request, int errcode, int type) { - int i; - hf_log (_T("aborting async request %p\n"), request); - i = 0; - while (i < MAX_ASYNC_REQUESTS) { - if (hfpd->d_request[i] == request && hfpd->d_request_type[i] == ASYNC_REQUEST_TEMP) { - /* ASYNC_REQUEST_TEMP = request is processing */ - sleep_millis (1); - i = 0; - continue; - } - i++; - } - i = release_async_request (hfpd, request); + int i; + hf_log(_T("aborting async request %p\n"), request); + i = 0; + while (i < MAX_ASYNC_REQUESTS) { + if (hfpd->d_request[i] == request && hfpd->d_request_type[i] == ASYNC_REQUEST_TEMP) { + /* ASYNC_REQUEST_TEMP = request is processing */ + sleep_millis(1); + i = 0; + continue; + } + i++; + } + i = release_async_request(hfpd, request); if (i >= 0) { - hf_log (_T("asyncronous request=%08X aborted, error=%d\n"), request, errcode); + hf_log(_T("asyncronous request=%08X aborted, error=%d\n"), request, errcode); } } -static void *hardfile_thread (void *devs); -static int start_thread (TrapContext *context, int unit) +static void *hardfile_thread(void *devs); +static int start_thread(TrapContext *context, int unit) { - struct hardfileprivdata *hfpd = &hardfpd[unit]; + struct hardfileprivdata *hfpd = &hardfpd[unit]; - if (hfpd->thread_running) - return 1; - memset (hfpd, 0, sizeof (struct hardfileprivdata)); - hfpd->base = m68k_areg(regs, 6); - init_comm_pipe (&hfpd->requests, 100, 1); - uae_sem_init (&hfpd->sync_sem, 0, 0); - uae_start_thread (_T("hardfile"), hardfile_thread, hfpd, &(hfpd->thread_id)); - uae_sem_wait (&hfpd->sync_sem); - return hfpd->thread_running; + if (hfpd->thread_running) + return 1; + memset(hfpd, 0, sizeof(struct hardfileprivdata)); + hfpd->base = m68k_areg(regs, 6); + init_comm_pipe(&hfpd->requests, 100, 1); + uae_sem_init(&hfpd->sync_sem, 0, 0); + uae_start_thread(_T("hardfile"), hardfile_thread, hfpd, NULL); + uae_sem_wait(&hfpd->sync_sem); + return hfpd->thread_running; } -static int mangleunit (int unit) +static int mangleunit(int unit) { - if (unit <= 99) - return unit; - if (unit == 100) - return 8; - if (unit == 110) - return 9; - return -1; + if (unit <= 99) + return unit; + if (unit == 100) + return 8; + if (unit == 110) + return 9; + return -1; } -static uae_u32 REGPARAM2 hardfile_open (TrapContext *context) +static uae_u32 REGPARAM2 hardfile_open(TrapContext *context) { - uaecptr ioreq = m68k_areg(regs, 1); /* IOReq */ - int unit = mangleunit(m68k_dreg (regs, 0)); - struct hardfileprivdata *hfpd = &hardfpd[unit]; - int err = IOERR_OPENFAIL; + uaecptr ioreq = m68k_areg(regs, 1); /* IOReq */ + int unit = mangleunit(m68k_dreg(regs, 0)); + struct hardfileprivdata *hfpd = &hardfpd[unit]; + int err = IOERR_OPENFAIL; /* boot device port size == 0!? KS 1.x size = 12??? - * Ignore message size, too many programs do not set it correct - * int size = get_word (ioreq + 0x12); - */ - /* Check unit number */ - if (unit >= 0) { - struct hardfiledata *hfd = get_hardfile_data (unit); - if (hfd && (hfd->handle_valid || hfd->drive_empty) && start_thread (context, unit)) { - put_word (hfpd->base + 32, get_word (hfpd->base + 32) + 1); - put_long (ioreq + 24, unit); /* io_Unit */ - put_byte (ioreq + 31, 0); /* io_Error */ - put_byte (ioreq + 8, 7); /* ln_type = NT_REPLYMSG */ - hf_log (_T("hardfile_open, unit %d (%d), OK\n"), unit, m68k_dreg (regs, 0)); - return 0; - } - } - if (unit < 1000 || is_hardfile(unit) == FILESYS_VIRTUAL) - err = 50; /* HFERR_NoBoard */ - hf_log (_T("hardfile_open, unit %d (%d), ERR=%d\n"), unit, m68k_dreg (regs, 0), err); - put_long (ioreq + 20, (uae_u32)err); - put_byte (ioreq + 31, (uae_u8)err); - return (uae_u32)err; + * Ignore message size, too many programs do not set it correct + * int size = get_word (ioreq + 0x12); + */ + /* Check unit number */ + if (unit >= 0) { + struct hardfiledata *hfd = get_hardfile_data(unit); + if (hfd && (hfd->handle_valid || hfd->drive_empty) && start_thread(context, unit)) { + put_word(hfpd->base + 32, get_word(hfpd->base + 32) + 1); + put_long(ioreq + 24, unit); /* io_Unit */ + put_byte(ioreq + 31, 0); /* io_Error */ + put_byte(ioreq + 8, 7); /* ln_type = NT_REPLYMSG */ + hf_log(_T("hardfile_open, unit %d (%d), OK\n"), unit, m68k_dreg(regs, 0)); + return 0; + } + } + if (unit < 1000 || is_hardfile(unit) == FILESYS_VIRTUAL || is_hardfile(unit) == FILESYS_CD) + err = 50; /* HFERR_NoBoard */ + hf_log(_T("hardfile_open, unit %d (%d), ERR=%d\n"), unit, m68k_dreg(regs, 0), err); + put_long(ioreq + 20, (uae_u32)err); + put_byte(ioreq + 31, (uae_u8)err); + return (uae_u32)err; } -static uae_u32 REGPARAM2 hardfile_close (TrapContext *context) +static uae_u32 REGPARAM2 hardfile_close(TrapContext *context) { - uaecptr request = m68k_areg(regs, 1); /* IOReq */ - int unit = mangleunit (get_long (request + 24)); - struct hardfileprivdata *hfpd = &hardfpd[unit]; + uaecptr request = m68k_areg(regs, 1); /* IOReq */ + int unit = mangleunit(get_long(request + 24)); + struct hardfileprivdata *hfpd = &hardfpd[unit]; - if (!hfpd) - return 0; - put_word (hfpd->base + 32, get_word (hfpd->base + 32) - 1); - if (get_word(hfpd->base + 32) == 0) - write_comm_pipe_u32 (&hfpd->requests, 0, 1); - return 0; + if (!hfpd) + return 0; + put_word(hfpd->base + 32, get_word(hfpd->base + 32) - 1); + if (get_word(hfpd->base + 32) == 0) + write_comm_pipe_u32(&hfpd->requests, 0, 1); + return 0; } -static uae_u32 REGPARAM2 hardfile_expunge (TrapContext *context) +static uae_u32 REGPARAM2 hardfile_expunge(TrapContext *context) { - return 0; /* Simply ignore this one... */ + return 0; /* Simply ignore this one... */ } -static void outofbounds (int cmd, uae_u64 offset, uae_u64 len, uae_u64 max) +static void outofbounds(int cmd, uae_u64 offset, uae_u64 len, uae_u64 max) { - write_log (_T("UAEHF: cmd %d: out of bounds, %08X-%08X + %08X-%08X > %08X-%08X\n"), cmd, - (uae_u32)(offset >> 32),(uae_u32)offset,(uae_u32)(len >> 32),(uae_u32)len, - (uae_u32)(max >> 32),(uae_u32)max); + write_log(_T("UAEHF: cmd %d: out of bounds, %08X-%08X + %08X-%08X > %08X-%08X\n"), cmd, + (uae_u32)(offset >> 32), (uae_u32)offset, (uae_u32)(len >> 32), (uae_u32)len, + (uae_u32)(max >> 32), (uae_u32)max); } -static void unaligned (int cmd, uae_u64 offset, uae_u64 len, int blocksize) +static void unaligned(int cmd, uae_u64 offset, uae_u64 len, int blocksize) { - write_log (_T("UAEHF: cmd %d: unaligned access, %08X-%08X, %08X-%08X, %08X\n"), cmd, - (uae_u32)(offset >> 32),(uae_u32)offset,(uae_u32)(len >> 32),(uae_u32)len, - blocksize); + write_log(_T("UAEHF: cmd %d: unaligned access, %08X-%08X, %08X-%08X, %08X\n"), cmd, + (uae_u32)(offset >> 32), (uae_u32)offset, (uae_u32)(len >> 32), (uae_u32)len, + blocksize); } -static uae_u32 hardfile_do_io (struct hardfiledata *hfd, struct hardfileprivdata *hfpd, uaecptr request) +static uae_u32 hardfile_do_io(struct hardfiledata *hfd, struct hardfileprivdata *hfpd, uaecptr request) { - uae_u32 dataptr, offset, actual = 0, cmd; - uae_u64 offset64; - int unit = get_long (request + 24); - uae_u32 error = 0, len; - int async = 0; + uae_u32 dataptr, offset, actual = 0, cmd; + uae_u64 offset64; + int unit = get_long(request + 24); + uae_u32 error = 0, len; + int async = 0; int bmask = hfd->ci.blocksize - 1; - cmd = get_word (request + 28); /* io_Command */ - dataptr = get_long (request + 40); - switch (cmd) - { + cmd = get_word(request + 28); /* io_Command */ + dataptr = get_long(request + 40); + switch (cmd) + { case CMD_READ: - if (nodisk (hfd)) - goto no_disk; - offset = get_long (request + 44); - len = get_long (request + 36); /* io_Length */ + if (nodisk(hfd)) + goto no_disk; + offset = get_long(request + 44); + len = get_long(request + 36); /* io_Length */ if (offset & bmask) { - unaligned (cmd, offset, len, hfd->ci.blocksize); - goto bad_command; - } - if (len & bmask) { - unaligned (cmd, offset, len, hfd->ci.blocksize); - goto bad_len; - } - if (len + offset > hfd->virtsize) { - outofbounds (cmd, offset, len, hfd->virtsize); - goto bad_len; - } - actual = (uae_u32)cmd_read (hfd, dataptr, offset, len); - break; + unaligned(cmd, offset, len, hfd->ci.blocksize); + goto bad_command; + } + if (len & bmask) { + unaligned(cmd, offset, len, hfd->ci.blocksize); + goto bad_len; + } + if (len + offset > hfd->virtsize) { + outofbounds(cmd, offset, len, hfd->virtsize); + goto bad_len; + } + actual = (uae_u32)cmd_read(hfd, dataptr, offset, len); + break; case TD_READ64: case NSCMD_TD_READ64: - if (nodisk (hfd)) - goto no_disk; - offset64 = get_long (request + 44) | ((uae_u64)get_long (request + 32) << 32); - len = get_long (request + 36); /* io_Length */ + if (nodisk(hfd)) + goto no_disk; + offset64 = get_long(request + 44) | ((uae_u64)get_long(request + 32) << 32); + len = get_long(request + 36); /* io_Length */ if (offset64 & bmask) { - unaligned (cmd, offset64, len, hfd->ci.blocksize); - goto bad_command; - } - if (len & bmask) { - unaligned (cmd, offset64, len, hfd->ci.blocksize); - goto bad_len; - } - if (len + offset64 > hfd->virtsize) { - outofbounds (cmd, offset64, len, hfd->virtsize); - goto bad_len; - } - actual = (uae_u32)cmd_read (hfd, dataptr, offset64, len); - break; + unaligned(cmd, offset64, len, hfd->ci.blocksize); + goto bad_command; + } + if (len & bmask) { + unaligned(cmd, offset64, len, hfd->ci.blocksize); + goto bad_len; + } + if (len + offset64 > hfd->virtsize) { + outofbounds(cmd, offset64, len, hfd->virtsize); + goto bad_len; + } + actual = (uae_u32)cmd_read(hfd, dataptr, offset64, len); + break; case CMD_WRITE: case CMD_FORMAT: /* Format */ - if (nodisk (hfd)) - goto no_disk; + if (nodisk(hfd)) + goto no_disk; if (hfd->ci.readonly || hfd->dangerous) { - error = 28; /* write protect */ - } else { - offset = get_long (request + 44); - len = get_long (request + 36); /* io_Length */ + error = 28; /* write protect */ + } + else { + offset = get_long(request + 44); + len = get_long(request + 36); /* io_Length */ if (offset & bmask) { - unaligned (cmd, offset, len, hfd->ci.blocksize); - goto bad_command; - } - if (len & bmask) { - unaligned (cmd, offset, len, hfd->ci.blocksize); - goto bad_len; - } - if (len + offset > hfd->virtsize) { - outofbounds (cmd, offset, len, hfd->virtsize); - goto bad_len; - } - actual = (uae_u32)cmd_write (hfd, dataptr, offset, len); - } - break; + unaligned(cmd, offset, len, hfd->ci.blocksize); + goto bad_command; + } + if (len & bmask) { + unaligned(cmd, offset, len, hfd->ci.blocksize); + goto bad_len; + } + if (len + offset > hfd->virtsize) { + outofbounds(cmd, offset, len, hfd->virtsize); + goto bad_len; + } + actual = (uae_u32)cmd_write(hfd, dataptr, offset, len); + } + break; case TD_WRITE64: case TD_FORMAT64: case NSCMD_TD_WRITE64: case NSCMD_TD_FORMAT64: - if (nodisk (hfd)) - goto no_disk; + if (nodisk(hfd)) + goto no_disk; if (hfd->ci.readonly || hfd->dangerous) { - error = 28; /* write protect */ - } else { - offset64 = get_long (request + 44) | ((uae_u64)get_long (request + 32) << 32); - len = get_long (request + 36); /* io_Length */ - if (offset64 & bmask) { - unaligned (cmd, offset64, len, hfd->ci.blocksize); - goto bad_command; - } - if (len & bmask) { - unaligned (cmd, offset64, len, hfd->ci.blocksize); - goto bad_len; - } - if (len + offset64 > hfd->virtsize) { - outofbounds (cmd, offset64, len, hfd->virtsize); - goto bad_len; - } - actual = (uae_u32)cmd_write (hfd, dataptr, offset64, len); - } - break; - - case NSCMD_DEVICEQUERY: - put_long (dataptr + 0, 0); - put_long (dataptr + 4, 16); /* size */ - put_word (dataptr + 8, NSDEVTYPE_TRACKDISK); - put_word (dataptr + 10, 0); - put_long (dataptr + 12, nscmd_cmd); - actual = 16; - break; - - case CMD_GETDRIVETYPE: - actual = DRIVE_NEWSTYLE; - break; - - case CMD_GETNUMTRACKS: - { - int cyl, cylsec, head, tracksec; - getchsx (hfd, &cyl, &cylsec, &head, &tracksec); - actual = cyl * head; - break; + error = 28; /* write protect */ } - - case CMD_GETGEOMETRY: - { - int cyl, cylsec, head, tracksec; - uae_u64 size; - getchsx (hfd, &cyl, &cylsec, &head, &tracksec); - put_long (dataptr + 0, hfd->ci.blocksize); - size = hfd->virtsize / hfd->ci.blocksize; - if (size > 0x00ffffffff) - size = 0xffffffff; - put_long (dataptr + 4, (uae_u32)size); - put_long (dataptr + 8, cyl); - put_long (dataptr + 12, cylsec); - put_long (dataptr + 16, head); - put_long (dataptr + 20, tracksec); - put_long (dataptr + 24, 0); /* bufmemtype */ - put_byte (dataptr + 28, 0); /* type = DG_DIRECT_ACCESS */ - put_byte (dataptr + 29, 0); /* flags */ + else { + offset64 = get_long(request + 44) | ((uae_u64)get_long(request + 32) << 32); + len = get_long(request + 36); /* io_Length */ + if (offset64 & bmask) { + unaligned(cmd, offset64, len, hfd->ci.blocksize); + goto bad_command; + } + if (len & bmask) { + unaligned(cmd, offset64, len, hfd->ci.blocksize); + goto bad_len; + } + if (len + offset64 > hfd->virtsize) { + outofbounds(cmd, offset64, len, hfd->virtsize); + goto bad_len; + } + actual = (uae_u32)cmd_write(hfd, dataptr, offset64, len); } break; + case NSCMD_DEVICEQUERY: + put_long(dataptr + 0, 0); + put_long(dataptr + 4, 16); /* size */ + put_word(dataptr + 8, NSDEVTYPE_TRACKDISK); + put_word(dataptr + 10, 0); + put_long(dataptr + 12, nscmd_cmd); + actual = 16; + break; + + case CMD_GETDRIVETYPE: + actual = DRIVE_NEWSTYLE; + break; + + case CMD_GETNUMTRACKS: + { + int cyl, cylsec, head, tracksec; + getchsx(hfd, &cyl, &cylsec, &head, &tracksec); + actual = cyl * head; + break; + } + + case CMD_GETGEOMETRY: + { + int cyl, cylsec, head, tracksec; + uae_u64 size; + getchsx(hfd, &cyl, &cylsec, &head, &tracksec); + put_long(dataptr + 0, hfd->ci.blocksize); + size = hfd->virtsize / hfd->ci.blocksize; + if (size > 0x00ffffffff) + size = 0xffffffff; + put_long(dataptr + 4, (uae_u32)size); + put_long(dataptr + 8, cyl); + put_long(dataptr + 12, cylsec); + put_long(dataptr + 16, head); + put_long(dataptr + 20, tracksec); + put_long(dataptr + 24, 0); /* bufmemtype */ + put_byte(dataptr + 28, 0); /* type = DG_DIRECT_ACCESS */ + put_byte(dataptr + 29, 0); /* flags */ + } + break; + case CMD_PROTSTATUS: if (hfd->ci.readonly || hfd->dangerous) - actual = -1; - else - actual = 0; - break; + actual = -1; + else + actual = 0; + break; case CMD_CHANGESTATE: - actual = hfd->drive_empty ? 1 :0; - break; + actual = hfd->drive_empty ? 1 : 0; + break; - /* Some commands that just do nothing and return zero */ + /* Some commands that just do nothing and return zero */ case CMD_UPDATE: case CMD_CLEAR: case CMD_MOTOR: case CMD_SEEK: case TD_SEEK64: case NSCMD_TD_SEEK64: - break; + break; case CMD_REMOVE: - hfpd->changeint = get_long (request + 40); - break; + hfpd->changeint = get_long(request + 40); + break; case CMD_CHANGENUM: - actual = hfpd->changenum; - break; + actual = hfpd->changenum; + break; case CMD_ADDCHANGEINT: - error = add_async_request (hfpd, request, ASYNC_REQUEST_CHANGEINT, get_long (request + 40)); - if (!error) - async = 1; - break; + error = add_async_request(hfpd, request, ASYNC_REQUEST_CHANGEINT, get_long(request + 40)); + if (!error) + async = 1; + break; case CMD_REMCHANGEINT: - release_async_request (hfpd, request); - break; - + release_async_request(hfpd, request); + break; + case HD_SCSICMD: /* SCSI */ - error = IOERR_NOCMD; - write_log (_T("UAEHF: HD_SCSICMD tried on regular HDF, unit %d\n"), unit); - break; + if (!hfd->ci.sectors && !hfd->ci.surfaces && !hfd->ci.reserved) { + error = handle_scsi(request, hfd); + } + else { /* we don't want users trashing their "partition" hardfiles with hdtoolbox */ + error = IOERR_NOCMD; + write_log(_T("UAEHF: HD_SCSICMD tried on regular HDF, unit %d\n"), unit); + } + break; case CD_EJECT: - error = IOERR_NOCMD; + if (hfd->ci.sectors && hfd->ci.surfaces) { + int len = get_long(request + 36); + if (len) { + if (hfd->drive_empty) { + hardfile_media_change(hfd, NULL, true, false); + } + else { + hardfile_media_change(hfd, NULL, false, false); + } + } + else { + if (hfd->drive_empty) { + hardfile_media_change(hfd, NULL, true, false); + } + } + } + else { + error = IOERR_NOCMD; + } break; -bad_command: + bad_command: error = IOERR_BADADDRESS; break; -bad_len: + bad_len: error = IOERR_BADLENGTH; break; -no_disk: + no_disk: error = 29; /* no disk */ break; default: - /* Command not understood. */ - error = IOERR_NOCMD; - break; - } - put_long (request + 32, actual); - put_byte (request + 31, error); + /* Command not understood. */ + error = IOERR_NOCMD; + break; + } + put_long(request + 32, actual); + put_byte(request + 31, error); - hf_log2 (_T("hf: unit=%d, request=%p, cmd=%d offset=%u len=%d, actual=%d error%=%d\n"), unit, request, - get_word(request + 28), get_long (request + 44), get_long (request + 36), actual, error); - - return async; + hf_log2(_T("hf: unit=%d, request=%p, cmd=%d offset=%u len=%d, actual=%d error%=%d\n"), unit, request, + get_word(request + 28), get_long(request + 44), get_long(request + 36), actual, error); + + return async; } -static uae_u32 REGPARAM2 hardfile_abortio (TrapContext *context) +static uae_u32 REGPARAM2 hardfile_abortio(TrapContext *context) { - uae_u32 request = m68k_areg(regs, 1); - int unit = mangleunit (get_long (request + 24)); -struct hardfiledata *hfd = get_hardfile_data (unit); - struct hardfileprivdata *hfpd = &hardfpd[unit]; + uae_u32 request = m68k_areg(regs, 1); + int unit = mangleunit(get_long(request + 24)); + struct hardfiledata *hfd = get_hardfile_data(unit); + struct hardfileprivdata *hfpd = &hardfpd[unit]; - hf_log2 (_T("uaehf.device abortio ")); - start_thread(context, unit); - if (!hfd || !hfpd || !hfpd->thread_running) { - put_byte (request + 31, 32); - hf_log2 (_T("error\n")); - return get_byte (request + 31); - } - put_byte (request + 31, -2); - hf_log2 (_T("unit=%d, request=%08X\n"), unit, request); - abort_async (hfpd, request, -2, 0); - return 0; + hf_log2(_T("uaehf.device abortio ")); + start_thread(context, unit); + if (!hfd || !hfpd || !hfpd->thread_running) { + put_byte(request + 31, 32); + hf_log2(_T("error\n")); + return get_byte(request + 31); + } + put_byte(request + 31, -2); + hf_log2(_T("unit=%d, request=%08X\n"), unit, request); + abort_async(hfpd, request, -2, 0); + return 0; } -static int hardfile_can_quick (uae_u32 command) +static int hardfile_can_quick(uae_u32 command) { - switch (command) - { - case CMD_REMCHANGEINT: - return -1; - case CMD_RESET: - case CMD_STOP: - case CMD_START: - case CMD_CHANGESTATE: - case CMD_PROTSTATUS: - case CMD_MOTOR: - case CMD_GETDRIVETYPE: - case CMD_GETGEOMETRY: - case CMD_GETNUMTRACKS: - case NSCMD_DEVICEQUERY: - return 1; - } - return 0; + switch (command) + { + case CMD_REMCHANGEINT: + return -1; + case CMD_RESET: + case CMD_STOP: + case CMD_START: + case CMD_CHANGESTATE: + case CMD_PROTSTATUS: + case CMD_MOTOR: + case CMD_GETDRIVETYPE: + case CMD_GETGEOMETRY: + case CMD_GETNUMTRACKS: + case NSCMD_DEVICEQUERY: + return 1; + } + return 0; } -static int hardfile_canquick (struct hardfiledata *hfd, uaecptr request) +static int hardfile_canquick(struct hardfiledata *hfd, uaecptr request) { - uae_u32 command = get_word (request + 28); - return hardfile_can_quick (command); + uae_u32 command = get_word(request + 28); + return hardfile_can_quick(command); } -static uae_u32 REGPARAM2 hardfile_beginio (TrapContext *context) +static uae_u32 REGPARAM2 hardfile_beginio(TrapContext *context) { - uae_u32 request = m68k_areg(regs, 1); - uae_u8 flags = get_byte (request + 30); - int cmd = get_word (request + 28); - int unit = mangleunit (get_long (request + 24)); - struct hardfiledata *hfd = get_hardfile_data (unit); - struct hardfileprivdata *hfpd = &hardfpd[unit]; + uae_u32 request = m68k_areg(regs, 1); + uae_u8 flags = get_byte(request + 30); + int cmd = get_word(request + 28); + int unit = mangleunit(get_long(request + 24)); + struct hardfiledata *hfd = get_hardfile_data(unit); + struct hardfileprivdata *hfpd = &hardfpd[unit]; int canquick; - put_byte (request + 8, NT_MESSAGE); - start_thread(context, unit); - if (!hfd || !hfpd || !hfpd->thread_running) { - put_byte (request + 31, 32); - return get_byte (request + 31); - } - put_byte (request + 31, 0); - canquick = hardfile_canquick (hfd, request); + put_byte(request + 8, NT_MESSAGE); + start_thread(context, unit); + if (!hfd || !hfpd || !hfpd->thread_running) { + put_byte(request + 31, 32); + return get_byte(request + 31); + } + put_byte(request + 31, 0); + canquick = hardfile_canquick(hfd, request); if (((flags & 1) && canquick) || (canquick < 0)) { - hf_log (_T("hf quickio unit=%d request=%p cmd=%d\n"), unit, request, cmd); + hf_log(_T("hf quickio unit=%d request=%p cmd=%d\n"), unit, request, cmd); if (hardfile_do_io(hfd, hfpd, request)) { - hf_log2 (_T("uaehf.device cmd %d bug with IO_QUICK\n"), cmd); + hf_log2(_T("uaehf.device cmd %d bug with IO_QUICK\n"), cmd); } if (!(flags & 1)) - uae_ReplyMsg (request); - return get_byte (request + 31); - } else { - hf_log2 (_T("hf asyncio unit=%d request=%p cmd=%d\n"), unit, request, cmd); - add_async_request (hfpd, request, ASYNC_REQUEST_TEMP, 0); - put_byte (request + 30, get_byte (request + 30) & ~1); - write_comm_pipe_u32 (&hfpd->requests, request, 1); - return 0; - } + uae_ReplyMsg(request); + return get_byte(request + 31); + } + else { + hf_log2(_T("hf asyncio unit=%d request=%p cmd=%d\n"), unit, request, cmd); + add_async_request(hfpd, request, ASYNC_REQUEST_TEMP, 0); + put_byte(request + 30, get_byte(request + 30) & ~1); + write_comm_pipe_u32(&hfpd->requests, request, 1); + return 0; + } } -static void *hardfile_thread (void *devs) +static void *hardfile_thread(void *devs) { - struct hardfileprivdata *hfpd = (struct hardfileprivdata *)devs; + struct hardfileprivdata *hfpd = (struct hardfileprivdata*)devs; - uae_set_thread_priority (NULL, 1); - hfpd->thread_running = 1; - uae_sem_post (&hfpd->sync_sem); - for (;;) { - uaecptr request = (uaecptr)read_comm_pipe_u32_blocking (&hfpd->requests); - uae_sem_wait (&change_sem); - if (!request) { -// dbg_rem_thread(hfpd->thread_id); - hfpd->thread_running = 0; - uae_sem_post (&hfpd->sync_sem); - uae_sem_post (&change_sem); - return 0; - } else if (hardfile_do_io (get_hardfile_data (hfpd - &hardfpd[0]), hfpd, request) == 0) { - put_byte (request + 30, get_byte (request + 30) & ~1); - release_async_request (hfpd, request); - uae_ReplyMsg (request); - } else { - hf_log2 (_T("async request %08X\n"), request); - } - uae_sem_post (&change_sem); - } -// dbg_rem_thread(hfpd->thread_id); + uae_set_thread_priority(NULL, 1); + hfpd->thread_running = 1; + uae_sem_post(&hfpd->sync_sem); + for (;;) { + uaecptr request = (uaecptr)read_comm_pipe_u32_blocking(&hfpd->requests); + uae_sem_wait(&change_sem); + if (!request) { + hfpd->thread_running = 0; + uae_sem_post(&hfpd->sync_sem); + uae_sem_post(&change_sem); + return 0; + } + else if (hardfile_do_io(get_hardfile_data(hfpd - &hardfpd[0]), hfpd, request) == 0) { + put_byte(request + 30, get_byte(request + 30) & ~1); + release_async_request(hfpd, request); + uae_ReplyMsg(request); + } + else { + hf_log2(_T("async request %08X\n"), request); + } + uae_sem_post(&change_sem); + } } -void hardfile_reset (void) +void hardfile_reset(void) { - int i, j; - struct hardfileprivdata *hfpd; + int i, j; + struct hardfileprivdata *hfpd; - for (i = 0; i < MAX_FILESYSTEM_UNITS; i++) { - hfpd = &hardfpd[i]; - if (hfpd->base && valid_address(hfpd->base, 36) && get_word(hfpd->base + 32) > 0) { - for (j = 0; j < MAX_ASYNC_REQUESTS; j++) { - uaecptr request; - if ((request = hfpd->d_request[j])) - abort_async (hfpd, request, 0, 0); - } - } - if(hfpd->thread_running) - { - uae_sem_wait (&change_sem); - write_comm_pipe_u32(&hfpd->requests, 0, 1); - uae_sem_post (&change_sem); - uae_sem_wait (&hfpd->sync_sem); - uae_sem_destroy (&hfpd->sync_sem); - destroy_comm_pipe (&hfpd->requests); - } - memset (hfpd, 0, sizeof (struct hardfileprivdata)); - } + for (i = 0; i < MAX_FILESYSTEM_UNITS; i++) { + hfpd = &hardfpd[i]; + if (hfpd->base && valid_address(hfpd->base, 36) && get_word(hfpd->base + 32) > 0) { + for (j = 0; j < MAX_ASYNC_REQUESTS; j++) { + uaecptr request; + if ((request = hfpd->d_request[i])) + abort_async(hfpd, request, 0, 0); + } + } + memset(hfpd, 0, sizeof(struct hardfileprivdata)); + } } -void hardfile_install (void) +void hardfile_install(void) { - uae_u32 functable, datatable; - uae_u32 initcode, openfunc, closefunc, expungefunc; - uae_u32 beginiofunc, abortiofunc; + uae_u32 functable, datatable; + uae_u32 initcode, openfunc, closefunc, expungefunc; + uae_u32 beginiofunc, abortiofunc; - if(change_sem != 0) - uae_sem_destroy(&change_sem); - change_sem = 0; - uae_sem_init (&change_sem, 0, 1); + uae_sem_init(&change_sem, 0, 1); - ROM_hardfile_resname = ds (_T("uaehf.device")); - ROM_hardfile_resid = ds (_T("UAE hardfile.device 0.3")); - nscmd_cmd = here (); - dw (NSCMD_DEVICEQUERY); - dw (CMD_RESET); - dw (CMD_READ); - dw (CMD_WRITE); - dw (CMD_UPDATE); - dw (CMD_CLEAR); - dw (CMD_START); - dw (CMD_STOP); - dw (CMD_FLUSH); - dw (CMD_MOTOR); - dw (CMD_SEEK); - dw (CMD_FORMAT); - dw (CMD_REMOVE); - dw (CMD_CHANGENUM); - dw (CMD_CHANGESTATE); - dw (CMD_PROTSTATUS); - dw (CMD_GETDRIVETYPE); - dw (CMD_GETGEOMETRY); - dw (CMD_ADDCHANGEINT); - dw (CMD_REMCHANGEINT); - dw (HD_SCSICMD); - dw (NSCMD_TD_READ64); - dw (NSCMD_TD_WRITE64); - dw (NSCMD_TD_SEEK64); - dw (NSCMD_TD_FORMAT64); - dw (0); + ROM_hardfile_resname = ds(_T("uaehf.device")); + ROM_hardfile_resid = ds(_T("UAE hardfile.device 0.3")); - /* initcode */ - initcode = filesys_initcode; + nscmd_cmd = here(); + dw(NSCMD_DEVICEQUERY); + dw(CMD_RESET); + dw(CMD_READ); + dw(CMD_WRITE); + dw(CMD_UPDATE); + dw(CMD_CLEAR); + dw(CMD_START); + dw(CMD_STOP); + dw(CMD_FLUSH); + dw(CMD_MOTOR); + dw(CMD_SEEK); + dw(CMD_FORMAT); + dw(CMD_REMOVE); + dw(CMD_CHANGENUM); + dw(CMD_CHANGESTATE); + dw(CMD_PROTSTATUS); + dw(CMD_GETDRIVETYPE); + dw(CMD_GETGEOMETRY); + dw(CMD_ADDCHANGEINT); + dw(CMD_REMCHANGEINT); + dw(HD_SCSICMD); + dw(NSCMD_TD_READ64); + dw(NSCMD_TD_WRITE64); + dw(NSCMD_TD_SEEK64); + dw(NSCMD_TD_FORMAT64); + dw(0); - /* Open */ - openfunc = here (); - calltrap (deftrap (hardfile_open)); dw (RTS); + /* initcode */ +#if 0 + initcode = here(); + calltrap(deftrap(hardfile_init)); dw(RTS); +#else + initcode = filesys_initcode; +#endif + /* Open */ + openfunc = here(); + calltrap(deftrap(hardfile_open)); dw(RTS); - /* Close */ - closefunc = here (); - calltrap (deftrap (hardfile_close)); dw (RTS); + /* Close */ + closefunc = here(); + calltrap(deftrap(hardfile_close)); dw(RTS); - /* Expunge */ - expungefunc = here (); - calltrap (deftrap (hardfile_expunge)); dw (RTS); + /* Expunge */ + expungefunc = here(); + calltrap(deftrap(hardfile_expunge)); dw(RTS); - /* BeginIO */ - beginiofunc = here (); - calltrap (deftrap (hardfile_beginio)); - dw (RTS); + /* BeginIO */ + beginiofunc = here(); + calltrap(deftrap(hardfile_beginio)); + dw(RTS); - /* AbortIO */ - abortiofunc = here (); - calltrap (deftrap (hardfile_abortio)); dw (RTS); + /* AbortIO */ + abortiofunc = here(); + calltrap(deftrap(hardfile_abortio)); dw(RTS); - /* FuncTable */ - functable = here (); - dl (openfunc); /* Open */ - dl (closefunc); /* Close */ - dl (expungefunc); /* Expunge */ - dl (EXPANSION_nullfunc); /* Null */ - dl (beginiofunc); /* BeginIO */ - dl (abortiofunc); /* AbortIO */ - dl (0xFFFFFFFFul); /* end of table */ + /* FuncTable */ + functable = here(); + dl(openfunc); /* Open */ + dl(closefunc); /* Close */ + dl(expungefunc); /* Expunge */ + dl(EXPANSION_nullfunc); /* Null */ + dl(beginiofunc); /* BeginIO */ + dl(abortiofunc); /* AbortIO */ + dl(0xFFFFFFFFul); /* end of table */ - /* DataTable */ - datatable = here (); - dw (0xE000); /* INITBYTE */ - dw (0x0008); /* LN_TYPE */ - dw (0x0300); /* NT_DEVICE */ - dw (0xC000); /* INITLONG */ - dw (0x000A); /* LN_NAME */ - dl (ROM_hardfile_resname); - dw (0xE000); /* INITBYTE */ - dw (0x000E); /* LIB_FLAGS */ - dw (0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */ - dw (0xD000); /* INITWORD */ - dw (0x0014); /* LIB_VERSION */ - dw (0x0004); /* 0.4 */ - dw (0xD000); - dw (0x0016); /* LIB_REVISION */ - dw (0x0000); - dw (0xC000); - dw (0x0018); /* LIB_IDSTRING */ - dl (ROM_hardfile_resid); - dw (0x0000); /* end of table */ + /* DataTable */ + datatable = here(); + dw(0xE000); /* INITBYTE */ + dw(0x0008); /* LN_TYPE */ + dw(0x0300); /* NT_DEVICE */ + dw(0xC000); /* INITLONG */ + dw(0x000A); /* LN_NAME */ + dl(ROM_hardfile_resname); + dw(0xE000); /* INITBYTE */ + dw(0x000E); /* LIB_FLAGS */ + dw(0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */ + dw(0xD000); /* INITWORD */ + dw(0x0014); /* LIB_VERSION */ + dw(0x0004); /* 0.4 */ + dw(0xD000); + dw(0x0016); /* LIB_REVISION */ + dw(0x0000); + dw(0xC000); + dw(0x0018); /* LIB_IDSTRING */ + dl(ROM_hardfile_resid); + dw(0x0000); /* end of table */ - ROM_hardfile_init = here (); - dl (0x00000100); /* ??? */ - dl (functable); - dl (datatable); - dl (initcode); + ROM_hardfile_init = here(); + dl(0x00000100); /* ??? */ + dl(functable); + dl(datatable); + dl(initcode); } diff --git a/src/osdep/hardfile_amiberry.cpp b/src/osdep/hardfile_amiberry.cpp index 93c9412c..bfac18a4 100644 --- a/src/osdep/hardfile_amiberry.cpp +++ b/src/osdep/hardfile_amiberry.cpp @@ -481,6 +481,31 @@ int hdf_write_target(struct hardfiledata* hfd, void* buffer, uae_u64 offset, int return got; } +int hdf_resize_target(struct hardfiledata *hfd, uae_u64 newsize) +{ + if (newsize < hfd->physsize) { + write_log("hdf_resize_target: truncation not implemented\n"); + return 0; + } + if (newsize == hfd->physsize) { + return 1; + } + /* Now, newsize must be larger than hfd->physsize, we seek to newsize - 1 + * and write a single 0 byte to make the file exactly newsize bytes big. */ + if (fseek(hfd->handle->f, newsize - 1, SEEK_SET) != 0) { + write_log("hdf_resize_target: fseek failed errno %d\n", errno); + return 0; + } + if (fwrite("", 1, 1, hfd->handle->f) != 1) { + write_log("hdf_resize_target: failed to write byte at position " + "%lld errno %d\n", newsize - 1, errno); + return 0; + } + write_log("hdf_resize_target: %lld -> %lld\n", hfd->physsize, newsize); + hfd->physsize = newsize; + return 1; +} + static void generatestorageproperty(struct uae_driveinfo *udi, int ignoreduplicates) { _tcscpy(udi->vendor_id, _T("UAE"));