diff --git a/BasiliskII/src/Unix/configure.ac b/BasiliskII/src/Unix/configure.ac index 63219dc6..1725bf93 100644 --- a/BasiliskII/src/Unix/configure.ac +++ b/BasiliskII/src/Unix/configure.ac @@ -77,6 +77,10 @@ AC_ARG_WITH(mon, [ --with-mon use mon as debugger [def AC_ARG_WITH(bincue, AS_HELP_STRING([--with-bincue], [Allow cdrom image files in bin/cue mode])) +AC_ARG_WITH(libvhd, + AS_HELP_STRING([--with-libvhd], [Enable VHD disk images])) + + dnl Canonical system information. AC_CANONICAL_HOST AC_CANONICAL_TARGET @@ -261,6 +265,22 @@ AS_IF([test "x$have_bincue" = "xyes" ], [ fi ]) +dnl LIBVHD +AS_IF([test "x$with_libvhd" = "xyes" ], [have_libvhd=yes], [have_libvhd=no]) +AS_IF([test "x$have_libvhd" = "xyes" ], [ + CPPFLAGS="$CPPFLAGS -DHAVE_LIBVHD" + LIBS="$LIBS -lvhd" + case $target_os in + linux*) + LIBS="$LIBS -luuid" + esac + AC_CHECK_LIB(vhd, vhd_open) + AC_CHECK_LIB(vhd, vhd_io_read) + AC_CHECK_LIB(vhd, vhd_io_write) + AC_CHECK_LIB(vhd, vhd_close) +]) + + dnl We want pthreads. Try libpthread first, then libc_r (FreeBSD), then PTL. HAVE_PTHREADS=yes @@ -717,6 +737,13 @@ if [[ "x$have_bincue" = "xyes" ]]; then EXTRASYSSRCS="$EXTRASYSSRCS bincue_unix.cpp" fi +dnl libvhd overrides + +if [[ "x$have_libvhd" = "xyes" ]]; then + EXTRASYSSRCS="$EXTRASYSSRCS vhd_unix.cpp" +fi + + dnl Use 68k CPU natively? WANT_NATIVE_M68K=no if [[ "x$HAVE_M68K" = "xyes" -a "x$CAN_NATIVE_M68K" = "xyes" ]]; then @@ -1654,6 +1681,7 @@ echo Basilisk II configuration summary: echo echo SDL support ............................ : $SDL_SUPPORT echo BINCUE support ......................... : $have_bincue +echo LIBVHD support ......................... : $have_libvhd echo XFree86 DGA support .................... : $WANT_XF86_DGA echo XFree86 VidMode support ................ : $WANT_XF86_VIDMODE echo fbdev DGA support ...................... : $WANT_FBDEV_DGA diff --git a/BasiliskII/src/Unix/sys_unix.cpp b/BasiliskII/src/Unix/sys_unix.cpp index 8ac4bc0a..4c29cd92 100644 --- a/BasiliskII/src/Unix/sys_unix.cpp +++ b/BasiliskII/src/Unix/sys_unix.cpp @@ -61,6 +61,11 @@ #include "bincue_unix.h" #endif +#if defined(HAVE_LIBVHD) +#include "vhd_unix.h" +#endif + + #define DEBUG 0 #include "debug.h" @@ -68,15 +73,15 @@ struct file_handle { char *name; // Copy of device/file name int fd; + bool is_file; // Flag: plain file or /dev/something? bool is_floppy; // Flag: floppy device bool is_cdrom; // Flag: CD-ROM device -#if defined(BINCUE) - bool is_bincue; // Flag: BIN CUE file -#endif bool read_only; // Copy of Sys_open() flag - loff_t start_byte; // Size of file header (if any) + + loff_t start_byte; // Size of file header (if any) loff_t file_size; // Size of file data (only valid if is_file is true) + bool is_media_present; // Flag: media is inserted and available #if defined(__linux__) @@ -89,8 +94,14 @@ struct file_handle { #endif #if defined(BINCUE) + bool is_bincue; // Flag: BIN CUE file void *bincue_fd; #endif + +#if defined(HAVE_LIBVHD) + bool is_vhd; // Flag: VHD file + void *vhd_fd; +#endif }; // Open file handles @@ -507,6 +518,19 @@ static bool is_drive_mounted(const char *dev_name, char *mount_name) /* * Open file/device, create new file handle (returns NULL on error) */ + +static file_handle *open_filehandle(const char *name) +{ + file_handle *fh = new file_handle; + memset(fh, 0, sizeof(file_handle)); + fh->name = strdup(name); + fh->fd = -1; +#if defined __MACOSX__ + fh->ioctl_fd = -1; + fh->ioctl_name = NULL; +#endif + return fh; +} void *Sys_open(const char *name, bool read_only) { @@ -562,27 +586,34 @@ void *Sys_open(const char *name, bool read_only) // Open file/device #if defined(BINCUE) - void *binfd = open_bincue(name); if (binfd) { - file_handle *fh = new file_handle; - fh->fd = 0; - fh->is_file = false; - fh->name = strdup(name); + file_handle *fh = open_filehandle(name); + D(bug("opening %s as bincue\n", name)); fh->bincue_fd = binfd; fh->is_bincue = true; - fh->read_only = true; - fh->start_byte = 0; - fh->is_floppy = false; - fh->is_cdrom = false; + fh->read_only = true; fh->is_media_present = true; -#if defined __MACOSX__ - fh->ioctl_fd = -1; - fh->ioctl_name = NULL; + sys_add_file_handle(fh); + return fh; + } #endif - sys_add_file_handle(fh); - return fh; - } + + +#if defined(HAVE_LIBVHD) + int vhdsize; + void *vhdfd = vhd_unix_open(name, &vhdsize, read_only); + if (vhdfd) { + file_handle *fh = open_filehandle(name); + D(bug("opening %s as vnd\n", name)); + fh->is_vhd = true; + fh->vhd_fd = vhdfd; + fh->read_only = read_only; + fh->file_size = vhdsize; + fh->is_media_present = true; + sys_add_file_handle(fh); + return fh; + } #endif #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__MACOSX__) @@ -596,26 +627,12 @@ void *Sys_open(const char *name, bool read_only) fd = open(name, O_RDONLY); } if (fd >= 0 || is_polled_media) { - file_handle *fh = new file_handle; - fh->name = strdup(name); + file_handle *fh = open_filehandle(name); fh->fd = fd; fh->is_file = is_file; fh->read_only = read_only; - fh->start_byte = 0; fh->is_floppy = is_floppy; fh->is_cdrom = is_cdrom; - fh->is_media_present = false; -#if defined __linux__ - fh->cdrom_cap = 0; -#endif -#if defined __MACOSX__ - fh->ioctl_fd = -1; - fh->ioctl_name = NULL; -#endif -#if defined(BINCUE) - fh->is_bincue = false; - fh->bincue_fd = NULL; -#endif if (fh->is_file) { fh->is_media_present = true; // Detect disk image file layout @@ -639,8 +656,6 @@ void *Sys_open(const char *name, bool read_only) if (fh->cdrom_cap < 0) fh->cdrom_cap = 0; } -#else - fh->cdrom_cap = 0; #endif #elif defined(__FreeBSD__) fh->is_floppy = ((st.st_rdev >> 16) == 2); @@ -649,8 +664,6 @@ void *Sys_open(const char *name, bool read_only) if (ioctl(fh->fd, CDIOCCAPABILITY, &fh->cdrom_cap) < 0) memset(&fh->cdrom_cap, 0, sizeof(fh->cdrom_cap)); } -#else - fh->cdrom_cap = 0; #endif #elif defined(__NetBSD__) fh->is_floppy = ((st.st_rdev >> 16) == 2); @@ -689,11 +702,14 @@ void Sys_close(void *arg) sys_remove_file_handle(fh); +#if defined(HAVE_LIBVHD) + if (fh->is_vhd) + vhd_unix_close(fh->vhd_fd); +#endif + #if defined(BINCUE) - if (fh->is_bincue) { - close_bincue(fh->bincue_fd); - fh->bincue_fd = NULL; - } + if (fh->is_bincue) + close_bincue(fh->bincue_fd); #endif if (fh->is_cdrom) @@ -718,9 +734,13 @@ size_t Sys_read(void *arg, void *buffer, loff_t offset, size_t length) return 0; #if defined(BINCUE) - if (fh->is_bincue) { - return read_bincue(fh->bincue_fd, buffer, offset, length); - } + if (fh->is_bincue) + return read_bincue(fh->bincue_fd, buffer, offset, length); +#endif + +#if defined(HAVE_LIBVHD) + if (fh->is_vhd) + return vhd_unix_read(fh->vhd_fd, buffer, offset, length); #endif // Seek to position @@ -743,6 +763,11 @@ size_t Sys_write(void *arg, void *buffer, loff_t offset, size_t length) if (!fh) return 0; +#if defined(HAVE_LIBVHD) + if (fh->is_vhd) + return vhd_unix_write(fh->vhd_fd, buffer, offset, length); +#endif + // Seek to position if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0) return 0; @@ -762,17 +787,21 @@ loff_t SysGetFileSize(void *arg) if (!fh) return true; +#if defined(BINCUE) + if (fh->is_bincue) + return size_bincue(fh->bincue_fd); +#endif + +#if defined(HAVE_LIBVHD) + if (fh->is_vhd) + return fh->file_size; +#endif + if (fh->is_file) return fh->file_size; else { long blocks; -#if defined(BINCUE) - if (fh->is_bincue) { - return size_bincue(fh->bincue_fd); - } -#endif #if defined(__linux__) - if (ioctl(fh->fd, BLKGETSIZE, &blocks) < 0) return 0; D(bug(" BLKGETSIZE returns %d blocks\n", blocks)); @@ -901,6 +930,11 @@ bool SysIsFixedDisk(void *arg) if (!fh) return true; +#if defined(HAVE_LIBVHD) + if (fh->is_vhd) + return true; +#endif + if (fh->is_file) return true; else if (fh->is_floppy || fh->is_cdrom) @@ -920,6 +954,11 @@ bool SysIsDiskInserted(void *arg) if (!fh) return false; +#if defined(HAVE_LIBVHD) + if (fh->is_vhd) + return true; +#endif + if (fh->is_file) { return true; @@ -1014,9 +1053,8 @@ bool SysCDReadTOC(void *arg, uint8 *toc) return false; #if defined(BINCUE) - if (fh->is_bincue){ + if (fh->is_bincue) return readtoc_bincue(fh->bincue_fd, toc); - } #endif if (fh->is_cdrom) { @@ -1162,10 +1200,8 @@ bool SysCDGetPosition(void *arg, uint8 *pos) return false; #if defined(BINCUE) - if (fh->is_bincue) { - + if (fh->is_bincue) return GetPosition_bincue(fh->bincue_fd, pos); - } #endif if (fh->is_cdrom) { @@ -1234,10 +1270,8 @@ bool SysCDPlay(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end return false; #if defined(BINCUE) - if (fh->is_bincue) { - return CDPlay_bincue(fh->bincue_fd, start_m, start_s, - start_f, end_m, end_s, end_f); - } + if (fh->is_bincue) + return CDPlay_bincue(fh->bincue_fd, start_m, start_s, start_f, end_m, end_s, end_f); #endif if (fh->is_cdrom) { @@ -1278,9 +1312,8 @@ bool SysCDPause(void *arg) return false; #if defined(BINCUE) - if (fh->is_bincue){ - return CDPause_bincue(fh->bincue_fd); - } + if (fh->is_bincue) + return CDPause_bincue(fh->bincue_fd); #endif if (fh->is_cdrom) { @@ -1307,9 +1340,8 @@ bool SysCDResume(void *arg) return false; #if defined(BINCUE) - if (fh->is_bincue) { - return CDResume_bincue(fh->bincue_fd); - } + if (fh->is_bincue) + return CDResume_bincue(fh->bincue_fd); #endif @@ -1337,9 +1369,8 @@ bool SysCDStop(void *arg, uint8 lead_out_m, uint8 lead_out_s, uint8 lead_out_f) return false; #if defined(BINCUE) - if (fh->is_bincue) { - return CDStop_bincue(fh->bincue_fd); - } + if (fh->is_bincue) + return CDStop_bincue(fh->bincue_fd); #endif diff --git a/BasiliskII/src/Unix/vhd_unix.cpp b/BasiliskII/src/Unix/vhd_unix.cpp new file mode 100644 index 00000000..5345d3ee --- /dev/null +++ b/BasiliskII/src/Unix/vhd_unix.cpp @@ -0,0 +1,124 @@ +/* + * vhd_unix.cpp -- support for disk images in vhd format + * + * (C) 2010 Geoffrey Brown + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "sysdeps.h" +#include "vhd_unix.h" +#include +#include +#include +#include +extern "C" { +#include +} +// libvhd.h defines DEBUG +#undef DEBUG +#define DEBUG 0 +#include "debug.h" + +void *vhd_unix_open(const char *name, int *size, bool read_only) +{ + int amode = read_only ? R_OK : (R_OK | W_OK); + int fid; + vhd_context_t *vhd; + + D(bug("vhd open %s\n", name)); + + if (access(name, amode)) { + D(bug("vhd open -- incorrect permissions %s\n", name)); + return NULL; + } + + if (! (fid = open(name, O_RDONLY))) { + D(bug("vhd open -- couldn't open file %s\n", name)); + return NULL; + } + else { + char buf[9]; + read(fid, buf, sizeof(buf)-1); + buf[8] = 0; + close(fid); + if (strcmp("conectix", buf) != 0) { + D(bug("vhd open -- not vhd magic = %s\n", buf)); + return NULL; + } + if (vhd = (vhd_context_t *) malloc(sizeof(vhd_context_t))) { + int err; + if (err = vhd_open(vhd, name, read_only ? + VHD_OPEN_RDONLY : VHD_OPEN_RDWR)) { + D(bug("vhd_open failed (%d)\n", err)); + free(vhd); + return NULL; + } + else { + *size = (int) vhd->footer.curr_size; + printf("VHD Open %s\n", name); + return (void *) vhd; + } + } + else { + D(bug("vhd open -- malloc failed\n")); + return NULL; + } + } +} + +int vhd_unix_read(void *arg, void *buffer, loff_t offset, size_t length) +{ + vhd_context_t *ctx = (vhd_context_t *) arg; + int err; + if ((offset % VHD_SECTOR_SIZE) || (length % VHD_SECTOR_SIZE)) { + printf("vhd read only supported on sector boundaries (%d)\n", + VHD_SECTOR_SIZE); + return 0; + } + if (err = vhd_io_read(ctx, (char *) buffer, offset / VHD_SECTOR_SIZE, + length / VHD_SECTOR_SIZE)){ + D(bug("vhd read error %d\n", err)); + return err; + } + else + return length; +} + +int vhd_unix_write(void *arg, void *buffer, loff_t offset, size_t length) +{ + int err; + vhd_context_t *ctx = (vhd_context_t *) arg; + + if ((offset % VHD_SECTOR_SIZE) || (length % VHD_SECTOR_SIZE)) { + printf("vhd write only supported on sector boundaries (%d)\n", + VHD_SECTOR_SIZE); + return 0; + } + if (err = vhd_io_write(ctx, (char *) buffer, offset/VHD_SECTOR_SIZE, + length/VHD_SECTOR_SIZE)) { + D(bug("vhd write error %d\n", err)); + return err; + } + else + return length; +} + +void vhd_unix_close(void *arg) +{ + D(bug("vhd close\n")); + vhd_close((vhd_context_t *) arg); + free(arg); +} diff --git a/BasiliskII/src/Unix/vhd_unix.h b/BasiliskII/src/Unix/vhd_unix.h new file mode 100644 index 00000000..a791b7ae --- /dev/null +++ b/BasiliskII/src/Unix/vhd_unix.h @@ -0,0 +1,29 @@ +/* + * vhd_unix.h -- support for disk images in vhd format + * + * (C) 2010 Geoffrey Brown + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef VHD_H +#define VHD_H + +void *vhd_unix_open(const char *name, int *size, bool read_only); +int vhd_unix_read(void *arg, void *buffer, loff_t offset, size_t length); +int vhd_unix_write(void *arg, void *buffer, loff_t offset, size_t length); +void vhd_unix_close(void *arg); + +#endif