From f136e7b0eb0ab42fc30d4e2594d0e79c97b0f427 Mon Sep 17 00:00:00 2001 From: arbee Date: Thu, 1 Aug 2019 21:40:55 -0400 Subject: [PATCH] harddisk: Support non-CHD harddisk images in raw and 2MG format [R. Belmont] --- src/devices/imagedev/harddriv.cpp | 56 ++++++++++++++++------ src/devices/imagedev/harddriv.h | 2 +- src/devices/machine/idehd.cpp | 2 +- src/lib/util/harddisk.cpp | 77 ++++++++++++++++++++++++++++--- src/lib/util/harddisk.h | 3 ++ 5 files changed, 118 insertions(+), 22 deletions(-) diff --git a/src/devices/imagedev/harddriv.cpp b/src/devices/imagedev/harddriv.cpp index 145ce0ebdbb..b4e93fcd200 100644 --- a/src/devices/imagedev/harddriv.cpp +++ b/src/devices/imagedev/harddriv.cpp @@ -75,7 +75,7 @@ harddisk_image_device::~harddisk_image_device() void harddisk_image_device::device_config_complete() { - add_format("chd", "CHD Hard drive", "chd,hd", hd_option_spec); + add_format("chd", "CHD Hard drive", "chd,hd,hdv,2mg", hd_option_spec); } const util::option_guide &harddisk_image_device::create_option_guide() const @@ -176,8 +176,11 @@ void harddisk_image_device::call_unload() m_hard_disk_handle = nullptr; } - m_origchd.close(); - m_diffchd.close(); + if (m_chd) + { + m_origchd.close(); + m_diffchd.close(); + } m_chd = nullptr; } @@ -227,7 +230,6 @@ static chd_error open_disk_diff(emu_options &options, const char *name, chd_file image_init_result harddisk_image_device::internal_load_hd() { chd_error err = CHDERR_NONE; - m_chd = nullptr; if (m_hard_disk_handle != nullptr) @@ -243,20 +245,24 @@ image_init_result harddisk_image_device::internal_load_hd() } else { - err = m_origchd.open(image_core_file(), true); - if (err == CHDERR_NONE) + if (is_filetype("chd")) { - m_chd = &m_origchd; - } - else if (err == CHDERR_FILE_NOT_WRITEABLE) - { - err = m_origchd.open(image_core_file(), false); + err = m_origchd.open(image_core_file(), true); + if (err == CHDERR_NONE) { - err = open_disk_diff(device().machine().options(), basename_noext(), m_origchd, m_diffchd); + m_chd = &m_origchd; + } + else if (err == CHDERR_FILE_NOT_WRITEABLE) + { + err = m_origchd.open(image_core_file(), false); if (err == CHDERR_NONE) { - m_chd = &m_diffchd; + err = open_disk_diff(device().machine().options(), basename_noext(), m_origchd, m_diffchd); + if (err == CHDERR_NONE) + { + m_chd = &m_diffchd; + } } } } @@ -269,6 +275,30 @@ image_init_result harddisk_image_device::internal_load_hd() if (m_hard_disk_handle != nullptr) return image_init_result::PASS; } + else + { + if (is_open()) + { + uint32_t skip = 0; + char header[64]; + + fseek(0, SEEK_SET); + fread(header, 64); + + // check for 2MG format + if (!memcmp(header, "2IMG", 4)) + { + skip = header[0x18] | (header[0x19] << 8) | (header[0x1a] << 16) | (header[0x1b] << 24); + osd_printf_verbose("harddriv: found 2MG, creator is %c%c%c%c, data at %08x\n", header[4], header[5], header[6], header[7], skip); + } + + m_hard_disk_handle = hard_disk_open(image_core_file(), skip); + if (m_hard_disk_handle != nullptr) + return image_init_result::PASS; + } + + return image_init_result::FAIL; + } /* if we had an error, close out the CHD */ m_origchd.close(); diff --git a/src/devices/imagedev/harddriv.h b/src/devices/imagedev/harddriv.h index 425b75d6eed..ab077ef8d38 100644 --- a/src/devices/imagedev/harddriv.h +++ b/src/devices/imagedev/harddriv.h @@ -51,7 +51,7 @@ public: virtual bool must_be_loaded() const override { return 0; } virtual bool is_reset_on_load() const override { return 0; } virtual const char *image_interface() const override { return m_interface; } - virtual const char *file_extensions() const override { return "chd,hd"; } + virtual const char *file_extensions() const override { return "chd,hd,hdv,2mg"; } virtual const util::option_guide &create_option_guide() const override; // specific implementation diff --git a/src/devices/machine/idehd.cpp b/src/devices/machine/idehd.cpp index e0ce5098e9a..e442e4475f6 100644 --- a/src/devices/machine/idehd.cpp +++ b/src/devices/machine/idehd.cpp @@ -838,7 +838,7 @@ void ide_hdd_device::device_reset() // build the features page uint32_t metalength; - if (m_handle->read_metadata (HARD_DISK_IDENT_METADATA_TAG, 0, &m_buffer[0], 512, metalength) == CHDERR_NONE) + if (m_handle && m_handle->read_metadata (HARD_DISK_IDENT_METADATA_TAG, 0, &m_buffer[0], 512, metalength) == CHDERR_NONE) { for( int w = 0; w < 256; w++ ) { diff --git a/src/lib/util/harddisk.cpp b/src/lib/util/harddisk.cpp index 31c6a36ed28..5db97e3417b 100644 --- a/src/lib/util/harddisk.cpp +++ b/src/lib/util/harddisk.cpp @@ -9,12 +9,10 @@ ***************************************************************************/ #include - #include "harddisk.h" - +#include "osdcore.h" #include - /*************************************************************************** TYPE DEFINITIONS ***************************************************************************/ @@ -22,6 +20,7 @@ struct hard_disk_file { chd_file * chd; /* CHD file */ + util::core_file *fhandle; /* core_file if not a CHD */ hard_disk_info info; /* hard disk info */ }; @@ -63,10 +62,49 @@ hard_disk_file *hard_disk_open(chd_file *chd) /* fill in the data */ file->chd = chd; + file->fhandle = nullptr; file->info.cylinders = cylinders; file->info.heads = heads; file->info.sectors = sectors; file->info.sectorbytes = sectorbytes; + file->info.fileoffset = 0; + return file; +} + +hard_disk_file *hard_disk_open(util::core_file &corefile, uint32_t skipoffs) +{ + hard_disk_file *file; + + /* allocate memory for the hard disk file */ + file = (hard_disk_file *)malloc(sizeof(hard_disk_file)); + if (file == nullptr) + return nullptr; + + file->chd = nullptr; + file->fhandle = &corefile; + file->info.sectorbytes = 512; + file->info.cylinders = 0; + file->info.heads = 0; + file->info.sectors = 0; + file->info.fileoffset = skipoffs; + + // attempt to guess geometry in case this is an ATA situation + for (uint32_t totalsectors = (corefile.size() - skipoffs) / file->info.sectorbytes; ; totalsectors++) + for (uint32_t cursectors = 63; cursectors > 1; cursectors--) + if (totalsectors % cursectors == 0) + { + uint32_t totalheads = totalsectors / cursectors; + for (uint32_t curheads = 16; curheads > 1; curheads--) + if (totalheads % curheads == 0) + { + file->info.cylinders = totalheads / curheads; + file->info.heads = curheads; + file->info.sectors = cursectors; + osd_printf_verbose("Guessed CHS of %d/%d/%d\n", file->info.cylinders, file->info.heads, file->info.sectors); + return file; + } + } + return file; } @@ -77,6 +115,11 @@ hard_disk_file *hard_disk_open(chd_file *chd) void hard_disk_close(hard_disk_file *file) { + if (file->fhandle) + { + file->fhandle->flush(); + } + free(file); } @@ -132,8 +175,18 @@ hard_disk_info *hard_disk_get_info(hard_disk_file *file) uint32_t hard_disk_read(hard_disk_file *file, uint32_t lbasector, void *buffer) { - chd_error err = file->chd->read_units(lbasector, buffer); - return (err == CHDERR_NONE); + if (file->chd) + { + chd_error err = file->chd->read_units(lbasector, buffer); + return (err == CHDERR_NONE); + } + else + { + uint32_t actual = 0; + file->fhandle->seek(file->info.fileoffset + (lbasector * file->info.sectorbytes), SEEK_SET); + actual = file->fhandle->read(buffer, file->info.sectorbytes); + return (actual == file->info.sectorbytes); + } } @@ -156,6 +209,16 @@ uint32_t hard_disk_read(hard_disk_file *file, uint32_t lbasector, void *buffer) uint32_t hard_disk_write(hard_disk_file *file, uint32_t lbasector, const void *buffer) { - chd_error err = file->chd->write_units(lbasector, buffer); - return (err == CHDERR_NONE); + if (file->chd) + { + chd_error err = file->chd->write_units(lbasector, buffer); + return (err == CHDERR_NONE); + } + else + { + uint32_t actual = 0; + file->fhandle->seek(file->info.fileoffset + (lbasector * file->info.sectorbytes), SEEK_SET); + actual = file->fhandle->write(buffer, file->info.sectorbytes); + return (actual == file->info.sectorbytes); + } } diff --git a/src/lib/util/harddisk.h b/src/lib/util/harddisk.h index c0551703ca7..2a4b727e7e7 100644 --- a/src/lib/util/harddisk.h +++ b/src/lib/util/harddisk.h @@ -29,6 +29,7 @@ struct hard_disk_info uint32_t heads; uint32_t sectors; uint32_t sectorbytes; + uint32_t fileoffset; // offset in the file where the HDD image starts. not valid for CHDs. }; @@ -38,6 +39,8 @@ struct hard_disk_info ***************************************************************************/ hard_disk_file *hard_disk_open(chd_file *chd); +hard_disk_file *hard_disk_open(util::core_file &corefile, uint32_t skipoffs); + void hard_disk_close(hard_disk_file *file); chd_file *hard_disk_get_chd(hard_disk_file *file);