mirror of
https://github.com/86Box/86Box.git
synced 2026-02-22 09:35:32 -07:00
Merge remote-tracking branch 'upstream/master' into feature/mtrr
This commit is contained in:
@@ -67,6 +67,8 @@ AppDir:
|
||||
- libxcb-shape0 # if QT:BOOL=ON
|
||||
- libxcb-shm0 # if QT:BOOL=ON
|
||||
- libxcb-xfixes0 # if QT:BOOL=ON
|
||||
- libxkbcommon-x11-0 # if QT:BOOL=ON
|
||||
- qtwayland5 # if QT:BOOL=ON
|
||||
- zlib1g
|
||||
files:
|
||||
exclude:
|
||||
|
||||
15
.ci/Jenkinsfile
vendored
15
.ci/Jenkinsfile
vendored
@@ -78,8 +78,7 @@ def dynarecSlugs = [
|
||||
]
|
||||
|
||||
def presets = [
|
||||
'Regular',
|
||||
'Debug'
|
||||
'Regular'
|
||||
]
|
||||
|
||||
def presetSlugs = [
|
||||
@@ -284,13 +283,19 @@ pipeline {
|
||||
def archName = archNames[archSlug]
|
||||
if (os == 'macOS')
|
||||
archName = archNamesMac[archSlug]
|
||||
dir("${dynarecNames[dynarec]}/$os - $archName") {
|
||||
ret = runBuild("-b \"$packageName\" \"$arch\" ${presetFlags[preset]} ${dynarecFlags[dynarec]} ${osFlags[os]} $buildFlags")
|
||||
dir(dynarecNames[dynarec]) {
|
||||
dir("$os - $archName") {
|
||||
ret = runBuild("-b \"$packageName\" \"$arch\" ${presetFlags[preset]} ${dynarecFlags[dynarec]} ${osFlags[os]} $buildFlags")
|
||||
if (presets.size() == 1)
|
||||
writeFile file: '.forcedir', text: ''
|
||||
}
|
||||
if ((osArchs.size() == 1) && (thisOsArchs.size() == 1))
|
||||
writeFile file: '.forcedir', text: ''
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
/* Archive resulting artifacts. */
|
||||
archiveArtifacts artifacts: "**/**/$packageName*"
|
||||
archiveArtifacts artifacts: "**/$packageName*, **/.forcedir", defaultExcludes: false
|
||||
} else {
|
||||
/* Fail this stage. */
|
||||
failStage()
|
||||
|
||||
11
.ci/build.sh
Normal file → Executable file
11
.ci/build.sh
Normal file → Executable file
@@ -316,6 +316,9 @@ then
|
||||
pacman -S --needed --noconfirm "$pkg"
|
||||
done
|
||||
fi
|
||||
|
||||
# Clean pacman cache when running under Jenkins to save disk space.
|
||||
[ "$CI" = "true" ] && rm -rf /var/cache/pacman/pkg
|
||||
|
||||
# Generate a new freetype DLL for this architecture.
|
||||
rm -f "$freetype_dll"
|
||||
@@ -584,7 +587,7 @@ else
|
||||
# ...and the ones we do want listed. Non-dev packages fill missing spots on the list.
|
||||
libpkgs=""
|
||||
longest_libpkg=0
|
||||
for pkg in libc6-dev libstdc++6 libopenal-dev libfreetype6-dev libx11-dev libsdl2-dev libpng-dev librtmidi-dev qtdeclarative5-dev libwayland-dev libevdev-dev libglib2.0-dev libslirp-dev libfaudio-dev libaudio-dev libjack-jackd2-dev libpipewire-0.3-dev libsamplerate0-dev libsndio-dev
|
||||
for pkg in libc6-dev libstdc++6 libopenal-dev libfreetype6-dev libx11-dev libsdl2-dev libpng-dev librtmidi-dev qtdeclarative5-dev libwayland-dev libevdev-dev libxkbcommon-x11-dev libglib2.0-dev libslirp-dev libfaudio-dev libaudio-dev libjack-jackd2-dev libpipewire-0.3-dev libsamplerate0-dev libsndio-dev
|
||||
do
|
||||
libpkgs="$libpkgs $pkg:$arch_deb"
|
||||
length=$(echo -n $pkg | sed 's/-dev$//' | sed "s/qtdeclarative/qt/" | wc -c)
|
||||
@@ -629,7 +632,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
||||
set(ENV{PKG_CONFIG_PATH} "")
|
||||
set(ENV{PKG_CONFIG_LIBDIR} "/usr/lib/$libdir/pkgconfig:/usr/share/$libdir/pkgconfig")
|
||||
set(ENV{PKG_CONFIG_LIBDIR} "/usr/lib/$libdir/pkgconfig:/usr/share/$libdir/pkgconfig:/usr/share/pkgconfig")
|
||||
|
||||
include("$(realpath "$toolchain_file")")
|
||||
EOF
|
||||
@@ -948,7 +951,6 @@ else
|
||||
-S "$prefix" -B "$prefix_build" || exit 99
|
||||
cmake --build "$prefix_build" -j$(nproc) || exit 99
|
||||
cmake --install "$prefix_build" || exit 99
|
||||
cp -p "$cwd_root/archive_tmp/usr/bin/fluidsynth" fluidsynth
|
||||
|
||||
# Build SDL2 for joystick and FAudio support, with most components
|
||||
# disabled to remove the dependencies on PulseAudio and libdrm.
|
||||
@@ -1014,7 +1016,7 @@ else
|
||||
mkdir -p "$icon_dir"
|
||||
cp -rp "$icon_size" "$icon_dir/apps"
|
||||
done
|
||||
project_icon=$(ls "$icon_base/"[0-9]*x[0-9]*/* | head -1 | grep -oP '/\K([^/]+)(?=\.[^\.]+$)')
|
||||
project_icon=$(find "$icon_base/"[0-9]*x[0-9]*/* -type f -name '*.png' -o -name '*.svg' | head -1 | grep -oP '/\K([^/]+)(?=\.[^\.]+$)')
|
||||
|
||||
# Archive executable, while also stripping it if requested.
|
||||
mkdir -p archive_tmp/usr/local/bin
|
||||
@@ -1139,6 +1141,7 @@ EOF
|
||||
--recipe AppImageBuilder-generated.yml --appdir "$(grep -oP '^\s+path: \K(.+)' AppImageBuilder-generated.yml)"
|
||||
status=$?
|
||||
[ $status -eq 0 ] && break
|
||||
[ $status -eq 127 ] && rm -rf /tmp/appimage_extracted_*
|
||||
done
|
||||
|
||||
# Remove appimage-builder binary on failure, just in case it's corrupted.
|
||||
|
||||
@@ -11,3 +11,5 @@ vulkan-headers
|
||||
MoltenVK
|
||||
qt5
|
||||
wget
|
||||
fluidsynth
|
||||
ghostscript
|
||||
|
||||
0
.ci/static2dll.sh
Normal file → Executable file
0
.ci/static2dll.sh
Normal file → Executable file
3
.github/workflows/cmake.yml
vendored
3
.github/workflows/cmake.yml
vendored
@@ -252,7 +252,10 @@ jobs:
|
||||
slug: -Qt
|
||||
packages: >-
|
||||
qtbase5-dev
|
||||
qtbase5-private-dev
|
||||
qttools5-dev
|
||||
libevdev-dev
|
||||
libxkbcommon-x11-dev
|
||||
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -34,6 +34,8 @@ Makefile
|
||||
*.tar.*
|
||||
*.AppImage
|
||||
/appimage-builder-cache
|
||||
/appimage-build
|
||||
/AppImageBuilder-generated.yml
|
||||
|
||||
# Visual Studio Code
|
||||
/.vs
|
||||
|
||||
@@ -36,7 +36,7 @@ if [ -z "${romversion}" ]; then
|
||||
# Get the latest ROM release from the GitHub API.
|
||||
romversion=$(curl --silent "https://api.github.com/repos/86Box/roms/releases/latest" |
|
||||
grep '"tag_name":' |
|
||||
sed -E 's/.*"([^"]+)".*/\1/')
|
||||
sed -E 's/.*"v([^"]+)".*/\1/')
|
||||
fi
|
||||
|
||||
# Switch to the repository root directory.
|
||||
|
||||
88
src/86box.c
88
src/86box.c
@@ -8,8 +8,6 @@
|
||||
*
|
||||
* Main emulator module where most things are controlled.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
@@ -150,47 +148,47 @@ uint64_t instru_run_ms = 0;
|
||||
|
||||
/* Configuration values. */
|
||||
int window_remember;
|
||||
int vid_resize; /* (C) allow resizing */
|
||||
int invert_display = 0; /* (C) invert the display */
|
||||
int suppress_overscan = 0; /* (C) suppress overscans */
|
||||
int scale = 0; /* (C) screen scale factor */
|
||||
int dpi_scale = 0; /* (C) DPI scaling of the emulated screen */
|
||||
int vid_api = 0; /* (C) video renderer */
|
||||
int vid_cga_contrast = 0; /* (C) video */
|
||||
int video_fullscreen = 0; /* (C) video */
|
||||
int video_fullscreen_scale = 0; /* (C) video */
|
||||
int video_fullscreen_first = 0; /* (C) video */
|
||||
int enable_overscan = 0; /* (C) video */
|
||||
int force_43 = 0; /* (C) video */
|
||||
int video_filter_method = 1; /* (C) video */
|
||||
int video_vsync = 0; /* (C) video */
|
||||
int video_framerate = -1; /* (C) video */
|
||||
char video_shader[512] = { '\0' }; /* (C) video */
|
||||
int vid_resize; /* (C) allow resizing */
|
||||
int invert_display = 0; /* (C) invert the display */
|
||||
int suppress_overscan = 0; /* (C) suppress overscans */
|
||||
int scale = 0; /* (C) screen scale factor */
|
||||
int dpi_scale = 0; /* (C) DPI scaling of the emulated screen */
|
||||
int vid_api = 0; /* (C) video renderer */
|
||||
int vid_cga_contrast = 0; /* (C) video */
|
||||
int video_fullscreen = 0; /* (C) video */
|
||||
int video_fullscreen_scale = 0; /* (C) video */
|
||||
int video_fullscreen_first = 0; /* (C) video */
|
||||
int enable_overscan = 0; /* (C) video */
|
||||
int force_43 = 0; /* (C) video */
|
||||
int video_filter_method = 1; /* (C) video */
|
||||
int video_vsync = 0; /* (C) video */
|
||||
int video_framerate = -1; /* (C) video */
|
||||
char video_shader[512] = { '\0' }; /* (C) video */
|
||||
bool serial_passthrough_enabled[SERIAL_MAX] = { 0, 0, 0, 0 }; /* (C) activation and kind of pass-through for serial ports */
|
||||
int bugger_enabled = 0; /* (C) enable ISAbugger */
|
||||
int postcard_enabled = 0; /* (C) enable POST card */
|
||||
int isamem_type[ISAMEM_MAX] = { 0, 0, 0, 0 }; /* (C) enable ISA mem cards */
|
||||
int isartc_type = 0; /* (C) enable ISA RTC card */
|
||||
int gfxcard[2] = { 0, 0 }; /* (C) graphics/video card */
|
||||
int show_second_monitors = 1; /* (C) show non-primary monitors */
|
||||
int sound_is_float = 1; /* (C) sound uses FP values */
|
||||
int voodoo_enabled = 0; /* (C) video option */
|
||||
int ibm8514_enabled = 0; /* (C) video option */
|
||||
int xga_enabled = 0; /* (C) video option */
|
||||
uint32_t mem_size = 0; /* (C) memory size (Installed on system board)*/
|
||||
uint32_t isa_mem_size = 0; /* (C) memory size (ISA Memory Cards) */
|
||||
int cpu_use_dynarec = 0; /* (C) cpu uses/needs Dyna */
|
||||
int cpu = 0; /* (C) cpu type */
|
||||
int fpu_type = 0; /* (C) fpu type */
|
||||
int time_sync = 0; /* (C) enable time sync */
|
||||
int confirm_reset = 1; /* (C) enable reset confirmation */
|
||||
int confirm_exit = 1; /* (C) enable exit confirmation */
|
||||
int confirm_save = 1; /* (C) enable save confirmation */
|
||||
int enable_discord = 0; /* (C) enable Discord integration */
|
||||
int pit_mode = -1; /* (C) force setting PIT mode */
|
||||
int fm_driver = 0; /* (C) select FM sound driver */
|
||||
int open_dir_usr_path = 0; /* default file open dialog directory of usr_path */
|
||||
int video_fullscreen_scale_maximized = 0; /* (C) Whether fullscreen scaling settings also apply when maximized. */
|
||||
int bugger_enabled = 0; /* (C) enable ISAbugger */
|
||||
int postcard_enabled = 0; /* (C) enable POST card */
|
||||
int isamem_type[ISAMEM_MAX] = { 0, 0, 0, 0 }; /* (C) enable ISA mem cards */
|
||||
int isartc_type = 0; /* (C) enable ISA RTC card */
|
||||
int gfxcard[2] = { 0, 0 }; /* (C) graphics/video card */
|
||||
int show_second_monitors = 1; /* (C) show non-primary monitors */
|
||||
int sound_is_float = 1; /* (C) sound uses FP values */
|
||||
int voodoo_enabled = 0; /* (C) video option */
|
||||
int ibm8514_enabled = 0; /* (C) video option */
|
||||
int xga_enabled = 0; /* (C) video option */
|
||||
uint32_t mem_size = 0; /* (C) memory size (Installed on system board)*/
|
||||
uint32_t isa_mem_size = 0; /* (C) memory size (ISA Memory Cards) */
|
||||
int cpu_use_dynarec = 0; /* (C) cpu uses/needs Dyna */
|
||||
int cpu = 0; /* (C) cpu type */
|
||||
int fpu_type = 0; /* (C) fpu type */
|
||||
int time_sync = 0; /* (C) enable time sync */
|
||||
int confirm_reset = 1; /* (C) enable reset confirmation */
|
||||
int confirm_exit = 1; /* (C) enable exit confirmation */
|
||||
int confirm_save = 1; /* (C) enable save confirmation */
|
||||
int enable_discord = 0; /* (C) enable Discord integration */
|
||||
int pit_mode = -1; /* (C) force setting PIT mode */
|
||||
int fm_driver = 0; /* (C) select FM sound driver */
|
||||
int open_dir_usr_path = 0; /* default file open dialog directory of usr_path */
|
||||
int video_fullscreen_scale_maximized = 0; /* (C) Whether fullscreen scaling settings also apply when maximized. */
|
||||
|
||||
/* Statistics. */
|
||||
extern int mmuflush;
|
||||
@@ -898,7 +896,7 @@ pc_init_modules(void)
|
||||
if (!video_card_available(gfxcard[1])) {
|
||||
char tempc[512] = { 0 };
|
||||
device_get_name(video_card_getdevice(gfxcard[1]), 0, tempc);
|
||||
swprintf(temp, sizeof_w(temp), (wchar_t *) "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card.", tempc);
|
||||
swprintf(temp, sizeof_w(temp), plat_get_string(IDS_2163), tempc);
|
||||
ui_msgbox_header(MBX_INFO, (wchar_t *) IDS_2129, temp);
|
||||
gfxcard[1] = 0;
|
||||
}
|
||||
@@ -1265,9 +1263,9 @@ pc_run(void)
|
||||
startblit();
|
||||
cpu_exec(cpu_s->rspeed / 100);
|
||||
#ifdef USE_GDBSTUB /* avoid a KBC FIFO overflow when CPU emulation is stalled */
|
||||
if (gdbstub_step == GDBSTUB_EXEC)
|
||||
// if (gdbstub_step == GDBSTUB_EXEC)
|
||||
#endif
|
||||
mouse_process();
|
||||
// mouse_process();
|
||||
joystick_process();
|
||||
endblit();
|
||||
|
||||
|
||||
@@ -40,9 +40,9 @@
|
||||
#include <86box/i2c.h>
|
||||
#include <86box/video.h>
|
||||
|
||||
int acpi_rtc_status = 0;
|
||||
int acpi_rtc_status = 0;
|
||||
atomic_int acpi_pwrbut_pressed = 0;
|
||||
int acpi_enabled = 0;
|
||||
int acpi_enabled = 0;
|
||||
|
||||
static double cpu_to_acpi;
|
||||
|
||||
@@ -1520,7 +1520,7 @@ acpi_ali_soft_smi_status_write(acpi_t *dev, uint8_t soft_smi)
|
||||
}
|
||||
|
||||
void
|
||||
acpi_pwrbtn_timer(void* priv)
|
||||
acpi_pwrbtn_timer(void *priv)
|
||||
{
|
||||
acpi_t *dev = (acpi_t *) priv;
|
||||
|
||||
|
||||
@@ -159,7 +159,15 @@ bin_init(const char *filename, int *error)
|
||||
tf->get_length = bin_get_length;
|
||||
tf->close = bin_close;
|
||||
} else {
|
||||
free(tf);
|
||||
/* From the check above, error may still be non-zero if opening a directory.
|
||||
* The error is set for viso to try and open the directory following this function.
|
||||
* However, we need to make sure the descriptor is closed. */
|
||||
if ((tf->file != NULL) && ((stats.st_mode & S_IFMT) == S_IFDIR)) {
|
||||
/* tf is freed by bin_close */
|
||||
bin_close(tf);
|
||||
} else {
|
||||
free(tf);
|
||||
}
|
||||
tf = NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -218,7 +218,7 @@ viso_convert_utf8(wchar_t *dest, const char *src, ssize_t buf_size)
|
||||
return p - dest;
|
||||
}
|
||||
|
||||
#define VISO_WRITE_STR_FUNC(func, dst_type, src_type, converter) \
|
||||
#define VISO_WRITE_STR_FUNC(func, dst_type, src_type, converter, bounds_chk) \
|
||||
static void \
|
||||
func(dst_type *dest, const src_type *src, ssize_t buf_size, int charset) \
|
||||
{ \
|
||||
@@ -284,7 +284,7 @@ viso_convert_utf8(wchar_t *dest, const char *src, ssize_t buf_size)
|
||||
\
|
||||
default: \
|
||||
/* Not valid for D or A, but valid for filenames. */ \
|
||||
if ((charset < VISO_CHARSET_FN) || (c > 0xffff)) \
|
||||
if ((charset < VISO_CHARSET_FN) || (bounds_chk)) \
|
||||
c = '_'; \
|
||||
break; \
|
||||
} \
|
||||
@@ -293,8 +293,8 @@ viso_convert_utf8(wchar_t *dest, const char *src, ssize_t buf_size)
|
||||
*dest++ = converter(c); \
|
||||
} \
|
||||
}
|
||||
VISO_WRITE_STR_FUNC(viso_write_string, uint8_t, char, )
|
||||
VISO_WRITE_STR_FUNC(viso_write_wstring, uint16_t, wchar_t, cpu_to_be16)
|
||||
VISO_WRITE_STR_FUNC(viso_write_string, uint8_t, char, , 0)
|
||||
VISO_WRITE_STR_FUNC(viso_write_wstring, uint16_t, wchar_t, cpu_to_be16, c > 0xffff)
|
||||
|
||||
static int
|
||||
viso_fill_fn_short(char *data, const viso_entry_t *entry, viso_entry_t **entries)
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Implementation of the ALi M1429 chipset.
|
||||
* Implementation of the ALi M1429 chipset.
|
||||
*
|
||||
* Note: This chipset has no datasheet, everything were done via
|
||||
* reverse engineering the BIOS of various machines using it.
|
||||
* Note: This chipset has no datasheet, everything were done via
|
||||
* reverse engineering the BIOS of various machines using it.
|
||||
*
|
||||
* Authors: Tiseno100,
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2020,2021 Tiseno100.
|
||||
* Copyright 2021,2021 Miran Grca.
|
||||
*
|
||||
* Authors: Tiseno100,
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2020-2021 Tiseno100.
|
||||
* Copyright 2021 Miran Grca.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -64,15 +66,14 @@
|
||||
Register 20h:
|
||||
Bits 2-1-0: Bus Clock Speed
|
||||
0 0 0: 7.1519Mhz (ATCLK2)
|
||||
0 0 1: CLK2IN/4
|
||||
0 1 0: CLK2IN/5
|
||||
0 1 1: CLK2IN/6
|
||||
1 0 0: CLK2IN/8
|
||||
1 0 1: CLK2IN/10
|
||||
1 1 0: CLK2IN/12
|
||||
0 0 1: CLK2IN/4
|
||||
0 1 0: CLK2IN/5
|
||||
0 1 1: CLK2IN/6
|
||||
1 0 0: CLK2IN/8
|
||||
1 0 1: CLK2IN/10
|
||||
1 1 0: CLK2IN/12
|
||||
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@@ -94,13 +95,11 @@
|
||||
#include <86box/smram.h>
|
||||
#include <86box/chipset.h>
|
||||
|
||||
#define GREEN dev->is_g /* Is G Variant */
|
||||
|
||||
#define GREEN dev->is_g /* Is G Variant */
|
||||
|
||||
#ifdef ENABLE_ALI1429_LOG
|
||||
int ali1429_do_log = ENABLE_ALI1429_LOG;
|
||||
|
||||
|
||||
static void
|
||||
ali1429_log(const char *fmt, ...)
|
||||
{
|
||||
@@ -113,27 +112,25 @@ ali1429_log(const char *fmt, ...)
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define ali1429_log(fmt, ...)
|
||||
# define ali1429_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t is_g, index, cfg_locked, reg_57h,
|
||||
regs[90];
|
||||
uint8_t is_g, index, cfg_locked, reg_57h,
|
||||
regs[90];
|
||||
} ali1429_t;
|
||||
|
||||
|
||||
static void
|
||||
ali1429_shadow_recalc(ali1429_t *dev)
|
||||
{
|
||||
uint32_t base, i, can_write, can_read;
|
||||
|
||||
shadowbios = (dev->regs[0x13] & 0x40) && (dev->regs[0x14] & 0x01);
|
||||
shadowbios = (dev->regs[0x13] & 0x40) && (dev->regs[0x14] & 0x01);
|
||||
shadowbios_write = (dev->regs[0x13] & 0x40) && (dev->regs[0x14] & 0x02);
|
||||
|
||||
can_write = (dev->regs[0x14] & 0x02) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
|
||||
can_read = (dev->regs[0x14] & 0x01) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
|
||||
can_read = (dev->regs[0x14] & 0x01) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
base = 0xc0000 + (i << 15);
|
||||
@@ -147,149 +144,151 @@ ali1429_shadow_recalc(ali1429_t *dev)
|
||||
flushmmucache_nopc();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ali1429_write(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
ali1429_t *dev = (ali1429_t *)priv;
|
||||
ali1429_t *dev = (ali1429_t *) priv;
|
||||
|
||||
switch (addr) {
|
||||
case 0x22:
|
||||
dev->index = val;
|
||||
break;
|
||||
case 0x22:
|
||||
dev->index = val;
|
||||
break;
|
||||
|
||||
case 0x23:
|
||||
case 0x23:
|
||||
#ifdef ENABLE_ALI1429_LOG
|
||||
if (dev->index != 0x03)
|
||||
ali1429_log("M1429: dev->regs[%02x] = %02x\n", dev->index, val);
|
||||
if (dev->index != 0x03)
|
||||
ali1429_log("M1429: dev->regs[%02x] = %02x\n", dev->index, val);
|
||||
#endif
|
||||
|
||||
if (dev->index == 0x03)
|
||||
dev->cfg_locked = (val != 0xc5);
|
||||
if (dev->index == 0x03)
|
||||
dev->cfg_locked = (val != 0xc5);
|
||||
|
||||
if (!dev->cfg_locked) {
|
||||
pclog("M1429: dev->regs[%02x] = %02x\n", dev->index, val);
|
||||
if (!dev->cfg_locked) {
|
||||
pclog("M1429: dev->regs[%02x] = %02x\n", dev->index, val);
|
||||
|
||||
/* Common M1429 Registers */
|
||||
switch (dev->index) {
|
||||
case 0x10: case 0x11:
|
||||
dev->regs[dev->index] = val;
|
||||
break;
|
||||
/* Common M1429 Registers */
|
||||
switch (dev->index) {
|
||||
case 0x10:
|
||||
case 0x11:
|
||||
dev->regs[dev->index] = val;
|
||||
break;
|
||||
|
||||
case 0x12:
|
||||
dev->regs[dev->index] = val;
|
||||
if(val & 4)
|
||||
mem_remap_top(128);
|
||||
else
|
||||
mem_remap_top(0);
|
||||
break;
|
||||
case 0x12:
|
||||
dev->regs[dev->index] = val;
|
||||
if (val & 4)
|
||||
mem_remap_top(128);
|
||||
else
|
||||
mem_remap_top(0);
|
||||
break;
|
||||
|
||||
case 0x13: case 0x14:
|
||||
dev->regs[dev->index] = val;
|
||||
ali1429_shadow_recalc(dev);
|
||||
break;
|
||||
case 0x13:
|
||||
case 0x14:
|
||||
dev->regs[dev->index] = val;
|
||||
ali1429_shadow_recalc(dev);
|
||||
break;
|
||||
|
||||
case 0x15: case 0x16:
|
||||
case 0x17:
|
||||
dev->regs[dev->index] = val;
|
||||
break;
|
||||
case 0x15:
|
||||
case 0x16:
|
||||
case 0x17:
|
||||
dev->regs[dev->index] = val;
|
||||
break;
|
||||
|
||||
case 0x18:
|
||||
dev->regs[dev->index] = (val & 0x8f) | 0x20;
|
||||
cpu_cache_ext_enabled = !!(val & 2);
|
||||
cpu_update_waitstates();
|
||||
break;
|
||||
case 0x18:
|
||||
dev->regs[dev->index] = (val & 0x8f) | 0x20;
|
||||
cpu_cache_ext_enabled = !!(val & 2);
|
||||
cpu_update_waitstates();
|
||||
break;
|
||||
|
||||
case 0x19: case 0x1a:
|
||||
case 0x1e:
|
||||
dev->regs[dev->index] = val;
|
||||
break;
|
||||
case 0x19:
|
||||
case 0x1a:
|
||||
case 0x1e:
|
||||
dev->regs[dev->index] = val;
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
dev->regs[dev->index] = val;
|
||||
case 0x20:
|
||||
dev->regs[dev->index] = val;
|
||||
|
||||
switch(val & 7) {
|
||||
case 0: case 7: /* Illegal */
|
||||
cpu_set_isa_speed(7159091);
|
||||
break;
|
||||
switch (val & 7) {
|
||||
case 0:
|
||||
case 7: /* Illegal */
|
||||
cpu_set_isa_speed(7159091);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
cpu_set_isa_speed(cpu_busspeed / 4);
|
||||
break;
|
||||
case 1:
|
||||
cpu_set_isa_speed(cpu_busspeed / 4);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
cpu_set_isa_speed(cpu_busspeed / 5);
|
||||
break;
|
||||
case 2:
|
||||
cpu_set_isa_speed(cpu_busspeed / 5);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
cpu_set_isa_speed(cpu_busspeed / 6);
|
||||
break;
|
||||
case 3:
|
||||
cpu_set_isa_speed(cpu_busspeed / 6);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
cpu_set_isa_speed(cpu_busspeed / 8);
|
||||
break;
|
||||
case 4:
|
||||
cpu_set_isa_speed(cpu_busspeed / 8);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
cpu_set_isa_speed(cpu_busspeed / 10);
|
||||
break;
|
||||
case 5:
|
||||
cpu_set_isa_speed(cpu_busspeed / 10);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
cpu_set_isa_speed(cpu_busspeed / 12);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
cpu_set_isa_speed(cpu_busspeed / 12);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x21 ... 0x27:
|
||||
dev->regs[dev->index] = val;
|
||||
break;
|
||||
}
|
||||
case 0x21 ... 0x27:
|
||||
dev->regs[dev->index] = val;
|
||||
break;
|
||||
}
|
||||
|
||||
/* M1429G Only Registers */
|
||||
if (GREEN) {
|
||||
switch (dev->index) {
|
||||
case 0x30 ... 0x41:
|
||||
case 0x43: case 0x45:
|
||||
case 0x4a:
|
||||
dev->regs[dev->index] = val;
|
||||
break;
|
||||
/* M1429G Only Registers */
|
||||
if (GREEN) {
|
||||
switch (dev->index) {
|
||||
case 0x30 ... 0x41:
|
||||
case 0x43:
|
||||
case 0x45:
|
||||
case 0x4a:
|
||||
dev->regs[dev->index] = val;
|
||||
break;
|
||||
|
||||
case 0x57:
|
||||
dev->reg_57h = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x57:
|
||||
dev->reg_57h = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
ali1429_read(uint16_t addr, void *priv)
|
||||
{
|
||||
ali1429_t *dev = (ali1429_t *)priv;
|
||||
uint8_t ret = 0xff;
|
||||
ali1429_t *dev = (ali1429_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
if ((addr == 0x23) && (dev->index >= 0x10) && (dev->index <= 0x4a))
|
||||
ret = dev->regs[dev->index];
|
||||
ret = dev->regs[dev->index];
|
||||
else if ((addr == 0x23) && (dev->index == 0x57))
|
||||
ret = dev->reg_57h;
|
||||
ret = dev->reg_57h;
|
||||
else if (addr == 0x22)
|
||||
ret = dev->index;
|
||||
ret = dev->index;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ali1429_close(void *priv)
|
||||
{
|
||||
ali1429_t *dev = (ali1429_t *)priv;
|
||||
ali1429_t *dev = (ali1429_t *) priv;
|
||||
|
||||
free(dev);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ali1429_defaults(ali1429_t *dev)
|
||||
{
|
||||
@@ -308,28 +307,27 @@ ali1429_defaults(ali1429_t *dev)
|
||||
|
||||
/* M1429G Default Registers */
|
||||
if (GREEN) {
|
||||
dev->regs[0x31] = 0x88;
|
||||
dev->regs[0x32] = 0xc0;
|
||||
dev->regs[0x38] = 0xe5;
|
||||
dev->regs[0x40] = 0xe3;
|
||||
dev->regs[0x41] = 2;
|
||||
dev->regs[0x45] = 0x80;
|
||||
dev->regs[0x31] = 0x88;
|
||||
dev->regs[0x32] = 0xc0;
|
||||
dev->regs[0x38] = 0xe5;
|
||||
dev->regs[0x40] = 0xe3;
|
||||
dev->regs[0x41] = 2;
|
||||
dev->regs[0x45] = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ali1429_init(const device_t *info)
|
||||
{
|
||||
ali1429_t *dev = (ali1429_t *)malloc(sizeof(ali1429_t));
|
||||
ali1429_t *dev = (ali1429_t *) malloc(sizeof(ali1429_t));
|
||||
memset(dev, 0, sizeof(ali1429_t));
|
||||
|
||||
dev->cfg_locked = 1;
|
||||
GREEN = info->local;
|
||||
GREEN = info->local;
|
||||
|
||||
/* M1429 Ports:
|
||||
22h Index Port
|
||||
23h Data Port
|
||||
22h Index Port
|
||||
23h Data Port
|
||||
*/
|
||||
io_sethandler(0x0022, 0x0002, ali1429_read, NULL, NULL, ali1429_write, NULL, NULL, dev);
|
||||
|
||||
@@ -341,29 +339,29 @@ ali1429_init(const device_t *info)
|
||||
}
|
||||
|
||||
const device_t ali1429_device = {
|
||||
.name = "ALi M1429",
|
||||
.name = "ALi M1429",
|
||||
.internal_name = "ali1429",
|
||||
.flags = 0,
|
||||
.local = 0,
|
||||
.init = ali1429_init,
|
||||
.close = ali1429_close,
|
||||
.reset = NULL,
|
||||
.flags = 0,
|
||||
.local = 0,
|
||||
.init = ali1429_init,
|
||||
.close = ali1429_close,
|
||||
.reset = NULL,
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
const device_t ali1429g_device = {
|
||||
.name = "ALi M1429G",
|
||||
.name = "ALi M1429G",
|
||||
.internal_name = "ali1429g",
|
||||
.flags = 0,
|
||||
.local = 1,
|
||||
.init = ali1429_init,
|
||||
.close = ali1429_close,
|
||||
.reset = NULL,
|
||||
.flags = 0,
|
||||
.local = 1,
|
||||
.init = ali1429_init,
|
||||
.close = ali1429_close,
|
||||
.reset = NULL,
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
@@ -38,138 +38,132 @@
|
||||
#include <86box/chipset.h>
|
||||
#include <86box/spd.h>
|
||||
|
||||
|
||||
#define MEM_STATE_SHADOW_R 0x01
|
||||
#define MEM_STATE_SHADOW_W 0x02
|
||||
#define MEM_STATE_SMRAM 0x04
|
||||
|
||||
#define MEM_STATE_SHADOW_R 0x01
|
||||
#define MEM_STATE_SHADOW_W 0x02
|
||||
#define MEM_STATE_SMRAM 0x04
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t index, cfg_locked,
|
||||
regs[16], pci_regs[256];
|
||||
uint8_t index, cfg_locked,
|
||||
regs[16], pci_regs[256];
|
||||
} ali1435_t;
|
||||
|
||||
|
||||
#define ENABLE_ALI1435_LOG 1
|
||||
#ifdef ENABLE_ALI1435_LOG
|
||||
int ali1435_do_log = ENABLE_ALI1435_LOG;
|
||||
|
||||
|
||||
static void
|
||||
ali1435_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (ali1435_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define ali1435_log(fmt, ...)
|
||||
# define ali1435_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
/* NOTE: We cheat here. The real ALi M1435 uses a level to edge triggered IRQ converter
|
||||
when the most siginificant bit is set. We work around that by manipulating the
|
||||
emulated PIC's ELCR register. */
|
||||
when the most siginificant bit is set. We work around that by manipulating the
|
||||
emulated PIC's ELCR register. */
|
||||
static void
|
||||
ali1435_update_irqs(ali1435_t *dev, int set)
|
||||
{
|
||||
uint8_t val;
|
||||
int i, reg;
|
||||
int shift, irq;
|
||||
int irq_map[8] = { -1, 5, 9, 10, 11, 12, 14, 15 };
|
||||
pic_t *temp_pic;
|
||||
int i, reg;
|
||||
int shift, irq;
|
||||
int irq_map[8] = { -1, 5, 9, 10, 11, 12, 14, 15 };
|
||||
pic_t *temp_pic;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
reg = 0x80 + (i >> 1);
|
||||
shift = (i & 1) << 2;
|
||||
val = (dev->pci_regs[reg] >> shift) & 0x0f;
|
||||
irq = irq_map[val & 0x07];
|
||||
if (irq == -1)
|
||||
continue;
|
||||
temp_pic = (irq >= 8) ? &pic2 : &pic;
|
||||
irq &= 7;
|
||||
if (set && (val & 0x08))
|
||||
temp_pic->elcr |= (1 << irq);
|
||||
else
|
||||
temp_pic->elcr &= ~(1 << irq);
|
||||
reg = 0x80 + (i >> 1);
|
||||
shift = (i & 1) << 2;
|
||||
val = (dev->pci_regs[reg] >> shift) & 0x0f;
|
||||
irq = irq_map[val & 0x07];
|
||||
if (irq == -1)
|
||||
continue;
|
||||
temp_pic = (irq >= 8) ? &pic2 : &pic;
|
||||
irq &= 7;
|
||||
if (set && (val & 0x08))
|
||||
temp_pic->elcr |= (1 << irq);
|
||||
else
|
||||
temp_pic->elcr &= ~(1 << irq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ali1435_pci_write(int func, int addr, uint8_t val, void *priv)
|
||||
{
|
||||
ali1435_t *dev = (ali1435_t *) priv;
|
||||
int irq, irq_map[8] = { -1, 5, 9, 10, 11, 12, 14, 15 };
|
||||
int irq, irq_map[8] = { -1, 5, 9, 10, 11, 12, 14, 15 };
|
||||
|
||||
ali1435_log("ali1435_write(%02X, %02X, %02X)\n", func, addr, val);
|
||||
|
||||
if (func > 0)
|
||||
return;
|
||||
return;
|
||||
|
||||
if ((addr < 0x04) || (addr == 0x06) || ((addr >= 0x08) && (addr <= 0x0b)))
|
||||
return;
|
||||
return;
|
||||
|
||||
if ((addr >= 0x0f) && (addr < 0x30))
|
||||
return;
|
||||
return;
|
||||
|
||||
if ((addr >= 0x34) && (addr < 0x40))
|
||||
return;
|
||||
return;
|
||||
|
||||
switch (addr) {
|
||||
/* Dummy PCI Config */
|
||||
case 0x04:
|
||||
dev->pci_regs[addr] = (val & 0x7f) | 0x07;
|
||||
break;
|
||||
/* Dummy PCI Config */
|
||||
case 0x04:
|
||||
dev->pci_regs[addr] = (val & 0x7f) | 0x07;
|
||||
break;
|
||||
|
||||
case 0x05:
|
||||
dev->pci_regs[addr] = (val & 0x01);
|
||||
break;
|
||||
case 0x05:
|
||||
dev->pci_regs[addr] = (val & 0x01);
|
||||
break;
|
||||
|
||||
/* Dummy PCI Status */
|
||||
case 0x07:
|
||||
dev->pci_regs[addr] &= ~(val & 0xb8);
|
||||
break;
|
||||
/* Dummy PCI Status */
|
||||
case 0x07:
|
||||
dev->pci_regs[addr] &= ~(val & 0xb8);
|
||||
break;
|
||||
|
||||
case 0x80: case 0x81:
|
||||
dev->pci_regs[addr] = val;
|
||||
ali1435_update_irqs(dev, 0);
|
||||
irq = irq_map[val & 0x07];
|
||||
if (irq >= 0) {
|
||||
ali1435_log("Set IRQ routing: INT %c -> %02X\n", 0x41 + ((addr & 0x01) << 1), irq);
|
||||
pci_set_irq_routing(PCI_INTA + ((addr & 0x01) << 1), irq);
|
||||
} else {
|
||||
ali1435_log("Set IRQ routing: INT %c -> FF\n", 0x41 + ((addr & 0x01) << 1));
|
||||
pci_set_irq_routing(PCI_INTA + ((addr & 0x01) << 1), PCI_IRQ_DISABLED);
|
||||
}
|
||||
irq = irq_map[(val >> 4) & 0x07];
|
||||
if (irq >= 0) {
|
||||
ali1435_log("Set IRQ routing: INT %c -> %02X\n", 0x42 + ((addr & 0x01) << 1), irq);
|
||||
pci_set_irq_routing(PCI_INTB + ((addr & 0x01) << 1), irq);
|
||||
} else {
|
||||
ali1435_log("Set IRQ routing: INT %c -> FF\n", 0x42 + ((addr & 0x01) << 1));
|
||||
pci_set_irq_routing(PCI_INTB + ((addr & 0x01) << 1), PCI_IRQ_DISABLED);
|
||||
}
|
||||
ali1435_update_irqs(dev, 1);
|
||||
break;
|
||||
case 0x80:
|
||||
case 0x81:
|
||||
dev->pci_regs[addr] = val;
|
||||
ali1435_update_irqs(dev, 0);
|
||||
irq = irq_map[val & 0x07];
|
||||
if (irq >= 0) {
|
||||
ali1435_log("Set IRQ routing: INT %c -> %02X\n", 0x41 + ((addr & 0x01) << 1), irq);
|
||||
pci_set_irq_routing(PCI_INTA + ((addr & 0x01) << 1), irq);
|
||||
} else {
|
||||
ali1435_log("Set IRQ routing: INT %c -> FF\n", 0x41 + ((addr & 0x01) << 1));
|
||||
pci_set_irq_routing(PCI_INTA + ((addr & 0x01) << 1), PCI_IRQ_DISABLED);
|
||||
}
|
||||
irq = irq_map[(val >> 4) & 0x07];
|
||||
if (irq >= 0) {
|
||||
ali1435_log("Set IRQ routing: INT %c -> %02X\n", 0x42 + ((addr & 0x01) << 1), irq);
|
||||
pci_set_irq_routing(PCI_INTB + ((addr & 0x01) << 1), irq);
|
||||
} else {
|
||||
ali1435_log("Set IRQ routing: INT %c -> FF\n", 0x42 + ((addr & 0x01) << 1));
|
||||
pci_set_irq_routing(PCI_INTB + ((addr & 0x01) << 1), PCI_IRQ_DISABLED);
|
||||
}
|
||||
ali1435_update_irqs(dev, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev->pci_regs[addr] = val;
|
||||
break;
|
||||
default:
|
||||
dev->pci_regs[addr] = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
ali1435_pci_read(int func, int addr, void *priv)
|
||||
{
|
||||
ali1435_t *dev = (ali1435_t *) priv;
|
||||
uint8_t ret;
|
||||
uint8_t ret;
|
||||
|
||||
ret = 0xff;
|
||||
|
||||
@@ -181,68 +175,65 @@ ali1435_pci_read(int func, int addr, void *priv)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ali1435_write(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
ali1435_t *dev = (ali1435_t *)priv;
|
||||
ali1435_t *dev = (ali1435_t *) priv;
|
||||
|
||||
switch (addr) {
|
||||
case 0x22:
|
||||
dev->index = val;
|
||||
break;
|
||||
case 0x22:
|
||||
dev->index = val;
|
||||
break;
|
||||
|
||||
case 0x23:
|
||||
/* #ifdef ENABLE_ALI1435_LOG
|
||||
if (dev->index != 0x03)
|
||||
ali1435_log("M1435: dev->regs[%02x] = %02x\n", dev->index, val);
|
||||
#endif */
|
||||
case 0x23:
|
||||
/* #ifdef ENABLE_ALI1435_LOG
|
||||
if (dev->index != 0x03)
|
||||
ali1435_log("M1435: dev->regs[%02x] = %02x\n", dev->index, val);
|
||||
#endif */
|
||||
|
||||
if (dev->index == 0x03)
|
||||
dev->cfg_locked = (val != 0x69);
|
||||
if (dev->index == 0x03)
|
||||
dev->cfg_locked = (val != 0x69);
|
||||
|
||||
if (!dev->cfg_locked) {
|
||||
pclog("M1435: dev->regs[%02x] = %02x\n", dev->index, val);
|
||||
if (!dev->cfg_locked) {
|
||||
pclog("M1435: dev->regs[%02x] = %02x\n", dev->index, val);
|
||||
|
||||
switch (dev->index) {
|
||||
/* PCI Mechanism select? */
|
||||
case 0x00:
|
||||
dev->regs[dev->index] = val;
|
||||
pclog("PMC = %i\n", val != 0xc8);
|
||||
pci_set_pmc(val != 0xc8);
|
||||
break;
|
||||
switch (dev->index) {
|
||||
/* PCI Mechanism select? */
|
||||
case 0x00:
|
||||
dev->regs[dev->index] = val;
|
||||
pclog("PMC = %i\n", val != 0xc8);
|
||||
pci_set_pmc(val != 0xc8);
|
||||
break;
|
||||
|
||||
/* ???? */
|
||||
case 0x06:
|
||||
dev->regs[dev->index] = val;
|
||||
break;
|
||||
/* ???? */
|
||||
case 0x06:
|
||||
dev->regs[dev->index] = val;
|
||||
break;
|
||||
|
||||
/* ???? */
|
||||
case 0x07:
|
||||
dev->regs[dev->index] = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* ???? */
|
||||
case 0x07:
|
||||
dev->regs[dev->index] = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
ali1435_read(uint16_t addr, void *priv)
|
||||
{
|
||||
ali1435_t *dev = (ali1435_t *)priv;
|
||||
uint8_t ret = 0xff;
|
||||
ali1435_t *dev = (ali1435_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
if ((addr == 0x23) && (dev->index < 0x10))
|
||||
ret = dev->regs[dev->index];
|
||||
ret = dev->regs[dev->index];
|
||||
else if (addr == 0x22)
|
||||
ret = dev->index;
|
||||
ret = dev->index;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ali1435_reset(void *priv)
|
||||
{
|
||||
@@ -258,13 +249,16 @@ ali1435_reset(void *priv)
|
||||
|
||||
memset(dev->pci_regs, 0, 256);
|
||||
|
||||
dev->pci_regs[0x00] = 0x25; dev->pci_regs[0x01] = 0x10; /*ALi*/
|
||||
dev->pci_regs[0x02] = 0x35; dev->pci_regs[0x03] = 0x14; /*M1435*/
|
||||
dev->pci_regs[0x00] = 0x25;
|
||||
dev->pci_regs[0x01] = 0x10; /*ALi*/
|
||||
dev->pci_regs[0x02] = 0x35;
|
||||
dev->pci_regs[0x03] = 0x14; /*M1435*/
|
||||
dev->pci_regs[0x04] = 0x07;
|
||||
dev->pci_regs[0x07] = 0x04;
|
||||
dev->pci_regs[0x0b] = 0x06;
|
||||
|
||||
dev->pci_regs[0x80] = 0x80; dev->pci_regs[0x81] = 0x00;
|
||||
dev->pci_regs[0x80] = 0x80;
|
||||
dev->pci_regs[0x81] = 0x00;
|
||||
|
||||
pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED);
|
||||
pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED);
|
||||
@@ -272,16 +266,14 @@ ali1435_reset(void *priv)
|
||||
pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ali1435_close(void *p)
|
||||
{
|
||||
ali1435_t *dev = (ali1435_t *)p;
|
||||
ali1435_t *dev = (ali1435_t *) p;
|
||||
|
||||
free(dev);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ali1435_init(const device_t *info)
|
||||
{
|
||||
@@ -291,8 +283,8 @@ ali1435_init(const device_t *info)
|
||||
dev->cfg_locked = 1;
|
||||
|
||||
/* M1435 Ports:
|
||||
22h Index Port
|
||||
23h Data Port
|
||||
22h Index Port
|
||||
23h Data Port
|
||||
*/
|
||||
io_sethandler(0x0022, 0x0002, ali1435_read, NULL, NULL, ali1435_write, NULL, NULL, dev);
|
||||
|
||||
@@ -309,15 +301,15 @@ ali1435_init(const device_t *info)
|
||||
}
|
||||
|
||||
const device_t ali1435_device = {
|
||||
.name = "Intel ALi M1435",
|
||||
.name = "Intel ALi M1435",
|
||||
.internal_name = "ali1435",
|
||||
.flags = DEVICE_PCI,
|
||||
.local = 0x00,
|
||||
.init = ali1435_init,
|
||||
.close = ali1435_close,
|
||||
.reset = ali1435_reset,
|
||||
.flags = DEVICE_PCI,
|
||||
.local = 0x00,
|
||||
.init = ali1435_init,
|
||||
.close = ali1435_close,
|
||||
.reset = ali1435_reset,
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
@@ -180,6 +180,9 @@ ali1489_defaults(ali1489_t *dev)
|
||||
dev->regs[0x3d] = 0x01;
|
||||
dev->regs[0x40] = 0x03;
|
||||
|
||||
pic_kbd_latch(0x01);
|
||||
pic_mouse_latch(0x00);
|
||||
|
||||
ali1489_shadow_recalc(dev);
|
||||
cpu_cache_int_enabled = 0;
|
||||
cpu_cache_ext_enabled = 0;
|
||||
@@ -295,6 +298,7 @@ ali1489_write(uint16_t addr, uint8_t val, void *priv)
|
||||
|
||||
case 0x2a: /* I/O Recovery Register */
|
||||
dev->regs[dev->index] = val;
|
||||
pic_mouse_latch(val & 0x80);
|
||||
break;
|
||||
|
||||
case 0x2b: /* Turbo Function Register */
|
||||
|
||||
@@ -153,7 +153,8 @@ ali1533_write(int func, int addr, uint8_t val, void *priv)
|
||||
case 0x41:
|
||||
/* TODO: Bit 7 selects keyboard controller type:
|
||||
0 = AT, 1 = PS/2 */
|
||||
keyboard_at_set_mouse_scan((val & 0x40) ? 1 : 0);
|
||||
pic_kbd_latch(!!(val & 0x80));
|
||||
pic_mouse_latch(!!(val & 0x40));
|
||||
dev->pci_conf[addr] = val & 0xbf;
|
||||
break;
|
||||
|
||||
@@ -454,9 +455,7 @@ ali1533_read(int func, int addr, void *priv)
|
||||
ret = 0x00;
|
||||
else {
|
||||
ret = dev->pci_conf[addr];
|
||||
if (addr == 0x41)
|
||||
ret |= (keyboard_at_get_mouse_scan() << 2);
|
||||
else if (addr == 0x58)
|
||||
if (addr == 0x58)
|
||||
ret = (ret & 0xbf) | (dev->ide_dev_enable ? 0x40 : 0x00);
|
||||
else if ((dev->type == 1) && ((addr >= 0x7c) && (addr <= 0xff)) && !dev->pmu_dev_enable) {
|
||||
dev->pmu_dev_enable = 1;
|
||||
@@ -1510,7 +1509,8 @@ ali1543_reset(void *priv)
|
||||
dev->pci_conf[0x0a] = 0x01;
|
||||
dev->pci_conf[0x0b] = 0x06;
|
||||
|
||||
ali1533_write(0, 0x48, 0x00, dev); // Disables all IRQ's
|
||||
ali1533_write(0, 0x41, 0x00, dev); /* Disables the keyboard and mouse IRQ latch. */
|
||||
ali1533_write(0, 0x48, 0x00, dev); /* Disables all IRQ's. */
|
||||
ali1533_write(0, 0x44, 0x00, dev);
|
||||
ali1533_write(0, 0x4d, 0x00, dev);
|
||||
ali1533_write(0, 0x53, 0x00, dev);
|
||||
|
||||
@@ -46,38 +46,40 @@ typedef struct ali6117_t {
|
||||
|
||||
/* Total size, Bank 0 size, Bank 1 size, Bank 2 size, Bank 3 size. */
|
||||
static uint32_t ali6117_modes[32][5] = {
|
||||
{ 1024, 512, 512, 0, 0 },
|
||||
{ 2048, 512, 512, 512, 512 },
|
||||
{ 3072, 512, 512, 2048, 0 },
|
||||
{ 5120, 512, 512, 2048, 2048 },
|
||||
{ 9216, 512, 512, 8192, 0 },
|
||||
{ 1024, 1024, 0, 0, 0 },
|
||||
{ 2048, 1024, 1024, 0, 0 },
|
||||
{ 4096, 1024, 1024, 2048, 0 },
|
||||
{ 6144, 1024, 1024, 2048, 2048 },
|
||||
{ 10240, 1024, 1024, 8192, 0 },
|
||||
{ 18432, 1024, 1024, 8192, 8192 },
|
||||
{ 3072, 1024, 2048, 0, 0 },
|
||||
{ 5120, 1024, 2048, 2048, 0 },
|
||||
{ 9216, 1024, 8192, 0, 0 },
|
||||
{ 2048, 2048, 0, 0, 0 },
|
||||
{ 4096, 2048, 2048, 0, 0 },
|
||||
{ 6144, 2048, 2048, 2048, 0 },
|
||||
{ 8192, 2048, 2048, 2048, 2048 },
|
||||
{ 12288, 2048, 2048, 8192, 0 },
|
||||
{ 20480, 2048, 2048, 8192, 8192 },
|
||||
{ 10240, 2048, 8192, 0, 0 },
|
||||
{ 18432, 2048, 8192, 8192, 0 },
|
||||
{ 26624, 2048, 8192, 8192, 8192 },
|
||||
{ 4096, 4096, 0, 0, 0 },
|
||||
{ 8192, 4096, 4096, 0, 0 },
|
||||
{ 24576, 4096, 4096, 8192, 8192 },
|
||||
{ 12288, 4096, 8192, 0, 0 },
|
||||
{ 8192, 8192, 0, 0, 0 },
|
||||
{ 16384, 8192, 8192, 0, 0 },
|
||||
{ 24576, 8192, 8192, 8192, 0 },
|
||||
{ 32768, 8192, 8192, 8192, 8192 },
|
||||
{ 65536, 32768, 32768, 0, 0 }
|
||||
// clang-format off
|
||||
{ 1024, 512, 512, 0, 0 },
|
||||
{ 2048, 512, 512, 512, 512 },
|
||||
{ 3072, 512, 512, 2048, 0 },
|
||||
{ 5120, 512, 512, 2048, 2048 },
|
||||
{ 9216, 512, 512, 8192, 0 },
|
||||
{ 1024, 1024, 0, 0, 0 },
|
||||
{ 2048, 1024, 1024, 0, 0 },
|
||||
{ 4096, 1024, 1024, 2048, 0 },
|
||||
{ 6144, 1024, 1024, 2048, 2048 },
|
||||
{ 10240, 1024, 1024, 8192, 0 },
|
||||
{ 18432, 1024, 1024, 8192, 8192 },
|
||||
{ 3072, 1024, 2048, 0, 0 },
|
||||
{ 5120, 1024, 2048, 2048, 0 },
|
||||
{ 9216, 1024, 8192, 0, 0 },
|
||||
{ 2048, 2048, 0, 0, 0 },
|
||||
{ 4096, 2048, 2048, 0, 0 },
|
||||
{ 6144, 2048, 2048, 2048, 0 },
|
||||
{ 8192, 2048, 2048, 2048, 2048 },
|
||||
{ 12288, 2048, 2048, 8192, 0 },
|
||||
{ 20480, 2048, 2048, 8192, 8192 },
|
||||
{ 10240, 2048, 8192, 0, 0 },
|
||||
{ 18432, 2048, 8192, 8192, 0 },
|
||||
{ 26624, 2048, 8192, 8192, 8192 },
|
||||
{ 4096, 4096, 0, 0, 0 },
|
||||
{ 8192, 4096, 4096, 0, 0 },
|
||||
{ 24576, 4096, 4096, 8192, 8192 },
|
||||
{ 12288, 4096, 8192, 0, 0 },
|
||||
{ 8192, 8192, 0, 0, 0 },
|
||||
{ 16384, 8192, 8192, 0, 0 },
|
||||
{ 24576, 8192, 8192, 8192, 0 },
|
||||
{ 32768, 8192, 8192, 8192, 8192 },
|
||||
{ 65536, 32768, 32768, 0, 0 }
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
#ifdef ENABLE_ALI6117_LOG
|
||||
@@ -300,6 +302,7 @@ ali6117_reg_write(uint16_t addr, uint8_t val, void *priv)
|
||||
case 0x36:
|
||||
val &= 0xf0;
|
||||
val |= dev->regs[dev->reg_offset];
|
||||
pic_mouse_latch(val & 0x40);
|
||||
break;
|
||||
|
||||
case 0x37:
|
||||
@@ -424,6 +427,8 @@ ali6117_reset(void *priv)
|
||||
/* On-board memory 15-16M is enabled by default. */
|
||||
mem_set_mem_state_both(0x00f00000, 0x00100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
|
||||
ali6117_bank_recalc(dev);
|
||||
|
||||
pic_mouse_latch(0x00);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,6 +478,9 @@ ali6117_init(const device_t *info)
|
||||
}
|
||||
}
|
||||
|
||||
if (!(dev->local & 0x08))
|
||||
pic_kbd_latch(0x01);
|
||||
|
||||
ali6117_reset(dev);
|
||||
|
||||
if (!(dev->local & 0x08))
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <86box/mem.h>
|
||||
#include <86box/smram.h>
|
||||
#include <86box/pci.h>
|
||||
#include <86box/pic.h>
|
||||
#include <86box/port_92.h>
|
||||
#include <86box/chipset.h>
|
||||
|
||||
@@ -388,6 +389,9 @@ ims8848_init(const device_t *info)
|
||||
|
||||
ims8848_reset(dev);
|
||||
|
||||
pic_kbd_latch(0x01);
|
||||
pic_mouse_latch(0x01);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <86box/mem.h>
|
||||
#include <86box/smram.h>
|
||||
#include <86box/pci.h>
|
||||
#include <86box/pic.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/pit.h>
|
||||
#include <86box/port_92.h>
|
||||
@@ -217,6 +218,7 @@ i420ex_write(int func, int addr, uint8_t val, void *priv)
|
||||
break;
|
||||
case 0x4e:
|
||||
dev->regs[addr] = (val & 0xf7);
|
||||
pic_mouse_latch(!!(val & 0x10));
|
||||
break;
|
||||
case 0x50:
|
||||
dev->regs[addr] = (val & 0x0f);
|
||||
@@ -387,7 +389,8 @@ i420ex_reset_hard(void *priv)
|
||||
|
||||
dev->regs[0x4c] = 0x4d;
|
||||
dev->regs[0x4e] = 0x03;
|
||||
/* Bits 2:1 of register 50h are 00 is 25 MHz, and 01 if 33 MHz, 10 and 11 are reserved. */
|
||||
pic_mouse_latch(0x00);
|
||||
/* Bits 2:1 of register 50h are 00 is 25 MHz, and 01 if 33 MHz, 10 and 11 are reserved. */
|
||||
if (cpu_busspeed >= 33333333)
|
||||
dev->regs[0x50] |= 0x02;
|
||||
dev->regs[0x51] = 0x80;
|
||||
@@ -436,6 +439,9 @@ i420ex_reset(void *p)
|
||||
|
||||
i420ex_write(0, 0x48, 0x00, p);
|
||||
|
||||
/* Disable the PIC mouse latch. */
|
||||
i420ex_write(0, 0x4e, 0x03, p);
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
i420ex_write(0, 0x59 + i, 0x00, p);
|
||||
|
||||
@@ -520,6 +526,8 @@ i420ex_init(const device_t *info)
|
||||
|
||||
i420ex_reset_hard(dev);
|
||||
|
||||
pic_kbd_latch(0x01);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
@@ -512,7 +512,7 @@ piix_write(int func, int addr, uint8_t val, void *priv)
|
||||
break;
|
||||
case 0x4e:
|
||||
fregs[0x4e] = val;
|
||||
keyboard_at_set_mouse_scan((val & 0x10) ? 1 : 0);
|
||||
pic_mouse_latch(!!(val & 0x10));
|
||||
if (dev->type >= 4)
|
||||
kbc_alias_update_io_mapping(dev);
|
||||
break;
|
||||
@@ -1159,9 +1159,7 @@ piix_read(int func, int addr, void *priv)
|
||||
if ((func <= dev->max_func) || ((func == 1) && (dev->max_func == 0))) {
|
||||
fregs = (uint8_t *) dev->regs[func];
|
||||
ret = fregs[addr];
|
||||
if ((func == 0) && (addr == 0x4e))
|
||||
ret |= keyboard_at_get_mouse_scan();
|
||||
else if ((func == 2) && (addr == 0xff))
|
||||
if ((func == 2) && (addr == 0xff))
|
||||
ret |= 0xef;
|
||||
|
||||
piix_log("PIIX function %i read: %02X from %02X\n", func, ret, addr);
|
||||
@@ -1277,6 +1275,7 @@ piix_reset_hard(piix_t *dev)
|
||||
fregs[0x0e] = ((dev->type > 1) || (dev->rev != 2)) ? 0x80 : 0x00;
|
||||
fregs[0x4c] = 0x4d;
|
||||
fregs[0x4e] = 0x03;
|
||||
pic_mouse_latch(0x00);
|
||||
fregs[0x60] = fregs[0x61] = fregs[0x62] = fregs[0x63] = 0x80;
|
||||
fregs[0x64] = (dev->type > 3) ? 0x10 : 0x00;
|
||||
fregs[0x69] = 0x02;
|
||||
@@ -1446,6 +1445,9 @@ piix_reset(void *p)
|
||||
piix_write(0, 0xa8, 0x0f, p);
|
||||
}
|
||||
|
||||
/* Disable the PIC mouse latch. */
|
||||
piix_write(0, 0x4e, 0x03, p);
|
||||
|
||||
if (dev->type == 5)
|
||||
piix_write(0, 0xe1, 0x40, p);
|
||||
piix_write(1, 0x04, 0x00, p);
|
||||
@@ -1532,9 +1534,8 @@ piix_speed_changed(void *priv)
|
||||
timer_on_auto(&dev->fast_off_timer, ((double) cpu_fast_off_val + 1) * dev->fast_off_period);
|
||||
}
|
||||
|
||||
static void
|
||||
*
|
||||
piix_init(const device_t *info)
|
||||
static void *
|
||||
piix_init(const device_t *info)
|
||||
{
|
||||
piix_t *dev = (piix_t *) malloc(sizeof(piix_t));
|
||||
memset(dev, 0, sizeof(piix_t));
|
||||
@@ -1680,6 +1681,8 @@ static void
|
||||
|
||||
// device_add(&i8254_sec_device);
|
||||
|
||||
pic_kbd_latch(0x01);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <86box/dma.h>
|
||||
#include <86box/mem.h>
|
||||
#include <86box/pci.h>
|
||||
#include <86box/pic.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/pit.h>
|
||||
#include <86box/port_92.h>
|
||||
@@ -201,6 +202,7 @@ sio_write(int func, int addr, uint8_t val, void *priv)
|
||||
case 0x4c:
|
||||
case 0x4d:
|
||||
dev->regs[addr] = (val & 0x7f);
|
||||
pic_mouse_latch(!!(val & 0x10));
|
||||
break;
|
||||
case 0x4f:
|
||||
dev->regs[addr] = val;
|
||||
@@ -392,6 +394,7 @@ sio_reset_hard(void *priv)
|
||||
dev->regs[0x4b] = 0x0f;
|
||||
dev->regs[0x4c] = 0x56;
|
||||
dev->regs[0x4d] = 0x40;
|
||||
pic_mouse_latch(0x00);
|
||||
dev->regs[0x4e] = 0x07;
|
||||
dev->regs[0x4f] = 0x4f;
|
||||
dev->regs[0x57] = 0x04;
|
||||
@@ -444,6 +447,9 @@ sio_reset(void *p)
|
||||
{
|
||||
sio_t *dev = (sio_t *) p;
|
||||
|
||||
/* Disable the PIC mouse latch. */
|
||||
sio_write(0, 0x4d, 0x40, p);
|
||||
|
||||
sio_write(0, 0x57, 0x04, p);
|
||||
|
||||
dma_set_params(1, 0xffffffff);
|
||||
@@ -538,6 +544,8 @@ sio_init(const device_t *info)
|
||||
|
||||
// device_add(&i8254_sec_device);
|
||||
|
||||
pic_kbd_latch(0x01);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
@@ -84,16 +84,20 @@ typedef struct scat_t {
|
||||
} scat_t;
|
||||
|
||||
static const uint8_t max_map[32] = {
|
||||
// clang-format off
|
||||
0, 1, 1, 1, 2, 3, 4, 8,
|
||||
4, 8, 12, 16, 20, 24, 28, 32,
|
||||
0, 5, 9, 13, 6, 10, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
// clang-format om
|
||||
};
|
||||
static const uint8_t max_map_sx[32] = {
|
||||
0, 1, 2, 1, 3, 4, 6, 10,
|
||||
5, 9, 13, 4, 8, 12, 16, 14,
|
||||
18, 22, 26, 20, 24, 28, 32, 18,
|
||||
20, 32, 0, 0, 0, 0, 0, 0
|
||||
// clang-format off
|
||||
0, 1, 2, 1, 3, 4, 6, 10,
|
||||
5, 9, 13, 4, 8, 12, 16, 14,
|
||||
18, 22, 26, 20, 24, 28, 32, 18,
|
||||
20, 32, 0, 0, 0, 0, 0, 0
|
||||
// clang-format om
|
||||
};
|
||||
static const uint8_t scatsx_external_is_RAS[33] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <86box/dma.h>
|
||||
#include <86box/mem.h>
|
||||
#include <86box/pci.h>
|
||||
#include <86box/pic.h>
|
||||
#include <86box/port_92.h>
|
||||
#include <86box/hdc_ide.h>
|
||||
#include <86box/hdc_ide_sff8038i.h>
|
||||
@@ -725,6 +726,9 @@ sis_5571_init(const device_t *info)
|
||||
|
||||
sis_5571_reset(dev);
|
||||
|
||||
pic_kbd_latch(0x01);
|
||||
pic_mouse_latch(0x01);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
@@ -135,89 +135,90 @@ sis_85c50x_smm_recalc(sis_85c50x_t *dev)
|
||||
static void
|
||||
sis_85c50x_write(int func, int addr, uint8_t val, void *priv)
|
||||
{
|
||||
sis_85c50x_t *dev = (sis_85c50x_t *) priv;
|
||||
sis_85c50x_t *dev = (sis_85c50x_t *) priv;
|
||||
|
||||
sis_85c50x_log("85C501: [W] (%02X, %02X) = %02X\n", func, addr, val);
|
||||
|
||||
if (func == 0x00) switch (addr) {
|
||||
case 0x04: /* Command - low byte */
|
||||
dev->pci_conf[addr] = (dev->pci_conf[addr] & 0xb4) | (val & 0x4b);
|
||||
break;
|
||||
case 0x07: /* Status - high byte */
|
||||
dev->pci_conf[addr] = ((dev->pci_conf[addr] & 0xf9) & ~(val & 0xf8)) | (val & 0x06);
|
||||
break;
|
||||
case 0x50:
|
||||
dev->pci_conf[addr] = val;
|
||||
break;
|
||||
case 0x51: /* Cache */
|
||||
dev->pci_conf[addr] = val;
|
||||
cpu_cache_ext_enabled = (val & 0x40);
|
||||
cpu_update_waitstates();
|
||||
break;
|
||||
case 0x52:
|
||||
dev->pci_conf[addr] = val;
|
||||
break;
|
||||
case 0x53: /* Shadow RAM */
|
||||
case 0x54:
|
||||
case 0x55:
|
||||
case 0x56:
|
||||
dev->pci_conf[addr] = val;
|
||||
sis_85c50x_shadow_recalc(dev);
|
||||
if (addr == 0x54)
|
||||
if (func == 0x00)
|
||||
switch (addr) {
|
||||
case 0x04: /* Command - low byte */
|
||||
dev->pci_conf[addr] = (dev->pci_conf[addr] & 0xb4) | (val & 0x4b);
|
||||
break;
|
||||
case 0x07: /* Status - high byte */
|
||||
dev->pci_conf[addr] = ((dev->pci_conf[addr] & 0xf9) & ~(val & 0xf8)) | (val & 0x06);
|
||||
break;
|
||||
case 0x50:
|
||||
dev->pci_conf[addr] = val;
|
||||
break;
|
||||
case 0x51: /* Cache */
|
||||
dev->pci_conf[addr] = val;
|
||||
cpu_cache_ext_enabled = (val & 0x40);
|
||||
cpu_update_waitstates();
|
||||
break;
|
||||
case 0x52:
|
||||
dev->pci_conf[addr] = val;
|
||||
break;
|
||||
case 0x53: /* Shadow RAM */
|
||||
case 0x54:
|
||||
case 0x55:
|
||||
case 0x56:
|
||||
dev->pci_conf[addr] = val;
|
||||
sis_85c50x_shadow_recalc(dev);
|
||||
if (addr == 0x54)
|
||||
sis_85c50x_smm_recalc(dev);
|
||||
break;
|
||||
case 0x57:
|
||||
case 0x58:
|
||||
case 0x59:
|
||||
case 0x5a:
|
||||
case 0x5c:
|
||||
case 0x5d:
|
||||
case 0x5e:
|
||||
case 0x61:
|
||||
case 0x62:
|
||||
case 0x63:
|
||||
case 0x67:
|
||||
case 0x68:
|
||||
case 0x6a:
|
||||
case 0x6b:
|
||||
case 0x6c:
|
||||
case 0x6d:
|
||||
case 0x6e:
|
||||
case 0x6f:
|
||||
dev->pci_conf[addr] = val;
|
||||
break;
|
||||
case 0x5f:
|
||||
dev->pci_conf[addr] = val & 0xfe;
|
||||
break;
|
||||
case 0x5b:
|
||||
dev->pci_conf[addr] = val;
|
||||
break;
|
||||
case 0x60: /* SMI */
|
||||
if ((dev->pci_conf[0x68] & 0x01) && !(dev->pci_conf[addr] & 0x02) && (val & 0x02)) {
|
||||
dev->pci_conf[0x69] |= 0x01;
|
||||
smi_raise();
|
||||
}
|
||||
dev->pci_conf[addr] = val & 0x3e;
|
||||
break;
|
||||
case 0x64: /* SMRAM */
|
||||
case 0x65:
|
||||
dev->pci_conf[addr] = val;
|
||||
sis_85c50x_smm_recalc(dev);
|
||||
break;
|
||||
case 0x57:
|
||||
case 0x58:
|
||||
case 0x59:
|
||||
case 0x5a:
|
||||
case 0x5c:
|
||||
case 0x5d:
|
||||
case 0x5e:
|
||||
case 0x61:
|
||||
case 0x62:
|
||||
case 0x63:
|
||||
case 0x67:
|
||||
case 0x68:
|
||||
case 0x6a:
|
||||
case 0x6b:
|
||||
case 0x6c:
|
||||
case 0x6d:
|
||||
case 0x6e:
|
||||
case 0x6f:
|
||||
dev->pci_conf[addr] = val;
|
||||
break;
|
||||
case 0x5f:
|
||||
dev->pci_conf[addr] = val & 0xfe;
|
||||
break;
|
||||
case 0x5b:
|
||||
dev->pci_conf[addr] = val;
|
||||
break;
|
||||
case 0x60: /* SMI */
|
||||
if ((dev->pci_conf[0x68] & 0x01) && !(dev->pci_conf[addr] & 0x02) && (val & 0x02)) {
|
||||
dev->pci_conf[0x69] |= 0x01;
|
||||
smi_raise();
|
||||
}
|
||||
dev->pci_conf[addr] = val & 0x3e;
|
||||
break;
|
||||
case 0x64: /* SMRAM */
|
||||
case 0x65:
|
||||
dev->pci_conf[addr] = val;
|
||||
sis_85c50x_smm_recalc(dev);
|
||||
break;
|
||||
case 0x66:
|
||||
dev->pci_conf[addr] = (val & 0x7f);
|
||||
break;
|
||||
case 0x69:
|
||||
dev->pci_conf[addr] &= ~(val);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x66:
|
||||
dev->pci_conf[addr] = (val & 0x7f);
|
||||
break;
|
||||
case 0x69:
|
||||
dev->pci_conf[addr] &= ~(val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
sis_85c50x_read(int func, int addr, void *priv)
|
||||
{
|
||||
sis_85c50x_t *dev = (sis_85c50x_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
if (func == 0x00)
|
||||
ret = dev->pci_conf[addr];
|
||||
@@ -234,41 +235,42 @@ sis_85c50x_sb_write(int func, int addr, uint8_t val, void *priv)
|
||||
|
||||
sis_85c50x_log("85C503: [W] (%02X, %02X) = %02X\n", func, addr, val);
|
||||
|
||||
if (func == 0x00) switch (addr) {
|
||||
case 0x04: /* Command */
|
||||
dev->pci_conf_sb[addr] = val & 0x0f;
|
||||
break;
|
||||
case 0x07: /* Status */
|
||||
dev->pci_conf_sb[addr] &= ~(val & 0x30);
|
||||
break;
|
||||
case 0x40: /* BIOS Control Register */
|
||||
dev->pci_conf_sb[addr] = val & 0x3f;
|
||||
break;
|
||||
case 0x41:
|
||||
case 0x42:
|
||||
case 0x43:
|
||||
case 0x44:
|
||||
/* INTA/B/C/D# Remapping Control Register */
|
||||
dev->pci_conf_sb[addr] = val & 0x8f;
|
||||
if (val & 0x80)
|
||||
pci_set_irq_routing(PCI_INTA + (addr - 0x41), PCI_IRQ_DISABLED);
|
||||
else
|
||||
pci_set_irq_routing(PCI_INTA + (addr - 0x41), val & 0xf);
|
||||
break;
|
||||
case 0x48: /* ISA Master/DMA Memory Cycle Control Register 1 */
|
||||
case 0x49: /* ISA Master/DMA Memory Cycle Control Register 2 */
|
||||
case 0x4a: /* ISA Master/DMA Memory Cycle Control Register 3 */
|
||||
case 0x4b: /* ISA Master/DMA Memory Cycle Control Register 4 */
|
||||
dev->pci_conf_sb[addr] = val;
|
||||
break;
|
||||
}
|
||||
if (func == 0x00)
|
||||
switch (addr) {
|
||||
case 0x04: /* Command */
|
||||
dev->pci_conf_sb[addr] = val & 0x0f;
|
||||
break;
|
||||
case 0x07: /* Status */
|
||||
dev->pci_conf_sb[addr] &= ~(val & 0x30);
|
||||
break;
|
||||
case 0x40: /* BIOS Control Register */
|
||||
dev->pci_conf_sb[addr] = val & 0x3f;
|
||||
break;
|
||||
case 0x41:
|
||||
case 0x42:
|
||||
case 0x43:
|
||||
case 0x44:
|
||||
/* INTA/B/C/D# Remapping Control Register */
|
||||
dev->pci_conf_sb[addr] = val & 0x8f;
|
||||
if (val & 0x80)
|
||||
pci_set_irq_routing(PCI_INTA + (addr - 0x41), PCI_IRQ_DISABLED);
|
||||
else
|
||||
pci_set_irq_routing(PCI_INTA + (addr - 0x41), val & 0xf);
|
||||
break;
|
||||
case 0x48: /* ISA Master/DMA Memory Cycle Control Register 1 */
|
||||
case 0x49: /* ISA Master/DMA Memory Cycle Control Register 2 */
|
||||
case 0x4a: /* ISA Master/DMA Memory Cycle Control Register 3 */
|
||||
case 0x4b: /* ISA Master/DMA Memory Cycle Control Register 4 */
|
||||
dev->pci_conf_sb[addr] = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
sis_85c50x_sb_read(int func, int addr, void *priv)
|
||||
{
|
||||
sis_85c50x_t *dev = (sis_85c50x_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
if (func == 0x00)
|
||||
ret = dev->pci_conf_sb[addr];
|
||||
|
||||
@@ -374,6 +374,9 @@ umc_8886_init(const device_t *info)
|
||||
|
||||
umc_8886_reset(dev);
|
||||
|
||||
pic_kbd_latch(0x01);
|
||||
pic_mouse_latch(0x01);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,13 +59,15 @@
|
||||
|
||||
/* Most revision numbers (PCI-ISA bridge or otherwise) were lifted from PCI device
|
||||
listings on forums, as VIA's datasheets are not very helpful regarding those. */
|
||||
#define VIA_PIPC_586A 0x05862500
|
||||
#define VIA_PIPC_586B 0x05864700
|
||||
#define VIA_PIPC_596A 0x05960900
|
||||
#define VIA_PIPC_596B 0x05962300
|
||||
#define VIA_PIPC_686A 0x06861400
|
||||
#define VIA_PIPC_686B 0x06864000
|
||||
#define VIA_PIPC_8231 0x82311000
|
||||
#define VIA_PIPC_586A 0x05862500
|
||||
#define VIA_PIPC_586B 0x05864700
|
||||
#define VIA_PIPC_596A 0x05960900
|
||||
#define VIA_PIPC_596B 0x05962300
|
||||
#define VIA_PIPC_686A 0x06861400
|
||||
#define VIA_PIPC_686B 0x06864000
|
||||
#define VIA_PIPC_8231 0x82311000
|
||||
|
||||
#define VIA_PIPC_FM_EMULATION 1
|
||||
|
||||
enum {
|
||||
TRAP_DRQ = 0,
|
||||
@@ -118,7 +120,7 @@ typedef struct _pipc_ {
|
||||
ide_regs[256],
|
||||
usb_regs[2][256],
|
||||
power_regs[256],
|
||||
ac97_regs[2][256], fmnmi_regs[4];
|
||||
ac97_regs[2][256], fmnmi_regs[4], fmnmi_status;
|
||||
|
||||
sff8038i_t *bm[2];
|
||||
nvr_t *nvr;
|
||||
@@ -220,6 +222,9 @@ pipc_reset_hard(void *priv)
|
||||
dev->pci_isa_regs[0x0b] = 0x06;
|
||||
dev->pci_isa_regs[0x0e] = 0x80;
|
||||
|
||||
pic_kbd_latch(0x01);
|
||||
pic_mouse_latch(dev->local >= VIA_PIPC_586B);
|
||||
|
||||
dev->pci_isa_regs[0x48] = 0x01;
|
||||
dev->pci_isa_regs[0x4a] = 0x04;
|
||||
dev->pci_isa_regs[0x4f] = 0x03;
|
||||
@@ -760,10 +765,10 @@ pipc_fmnmi_handlers(pipc_t *dev, uint8_t modem)
|
||||
static uint8_t
|
||||
pipc_fm_read(uint16_t addr, void *priv)
|
||||
{
|
||||
#ifdef VIA_PIPC_FM_EMULATION
|
||||
uint8_t ret = 0x00;
|
||||
#else
|
||||
pipc_t *dev = (pipc_t *) priv;
|
||||
#ifdef VIA_PIPC_FM_EMULATION
|
||||
uint8_t ret = ((addr & 0x03) == 0x00) ? dev->fmnmi_status : 0x00;
|
||||
#else
|
||||
uint8_t ret = dev->sb->opl.read(addr, dev->sb->opl.priv);
|
||||
#endif
|
||||
|
||||
@@ -784,12 +789,26 @@ pipc_fm_write(uint16_t addr, uint8_t val, void *priv)
|
||||
index port, and only fires NMI/SMI when writing to the data port. */
|
||||
if (!(addr & 0x01)) {
|
||||
dev->fmnmi_regs[0x00] = (addr & 0x02) ? 0x02 : 0x01;
|
||||
dev->fmnmi_regs[0x01] = val;
|
||||
} else {
|
||||
dev->fmnmi_regs[0x02] = val;
|
||||
} else {
|
||||
dev->fmnmi_regs[0x01] = val;
|
||||
|
||||
/* TODO: Probe how real hardware handles OPL timers. This assumed implementation
|
||||
just sets the relevant interrupt flags as soon as a timer is started. */
|
||||
if (!(addr & 0x02) && (dev->fmnmi_regs[0x02] == 0x04)) {
|
||||
if (val & 0x80)
|
||||
dev->fmnmi_status = 0x00;
|
||||
if ((val & 0x41) == 0x01)
|
||||
dev->fmnmi_status |= 0x40;
|
||||
if ((val & 0x22) == 0x02)
|
||||
dev->fmnmi_status |= 0x20;
|
||||
if (dev->fmnmi_status & 0x60)
|
||||
dev->fmnmi_status |= 0x80;
|
||||
}
|
||||
|
||||
/* Fire NMI/SMI if enabled. */
|
||||
if (dev->ac97_regs[0][0x48] & 0x01) {
|
||||
pipc_log("PIPC: Raising %s\n", (dev->ac97_regs[0][0x48] & 0x04) ? "SMI" : "NMI");
|
||||
if (dev->ac97_regs[0][0x48] & 0x04)
|
||||
smi_raise();
|
||||
else
|
||||
@@ -1047,6 +1066,11 @@ pipc_write(int func, int addr, uint8_t val, void *priv)
|
||||
|
||||
break;
|
||||
|
||||
case 0x44:
|
||||
if (dev->local < VIA_PIPC_586B)
|
||||
pic_mouse_latch(val & 0x01);
|
||||
break;
|
||||
|
||||
case 0x47:
|
||||
if (val & 0x01)
|
||||
trc_write(0x0047, (val & 0x80) ? 0x06 : 0x04, NULL);
|
||||
@@ -1569,6 +1593,9 @@ pipc_reset(void *p)
|
||||
else
|
||||
pipc_write(1, 0x40, 0x00, p);
|
||||
|
||||
if (dev->local < VIA_PIPC_586B)
|
||||
pipc_write(0, 0x44, 0x00, p);
|
||||
|
||||
pipc_write(0, 0x77, 0x00, p);
|
||||
}
|
||||
|
||||
|
||||
@@ -857,7 +857,7 @@ load_ports(void)
|
||||
serial_passthrough_enabled[c] = !!ini_section_get_int(cat, temp, 0);
|
||||
|
||||
if (serial_passthrough_enabled[c])
|
||||
config_log("Serial Port %d: passthrough enabled.\n\n", c+1);
|
||||
config_log("Serial Port %d: passthrough enabled.\n\n", c + 1);
|
||||
}
|
||||
|
||||
for (c = 0; c < PARALLEL_MAX; c++) {
|
||||
@@ -2345,7 +2345,7 @@ save_input_devices(void)
|
||||
} else {
|
||||
ini_section_delete_var(cat, "tablet_tool_type");
|
||||
}
|
||||
|
||||
|
||||
ini_delete_section_if_empty(config, cat);
|
||||
}
|
||||
|
||||
@@ -2540,7 +2540,7 @@ save_storage_controllers(void)
|
||||
ini_section_delete_var(cat, "cdrom_interface");
|
||||
else
|
||||
ini_section_set_string(cat, "cdrom_interface",
|
||||
cdrom_interface_get_internal_name(cdrom_interface_current));
|
||||
cdrom_interface_get_internal_name(cdrom_interface_current));
|
||||
|
||||
if (ide_ter_enabled == 0)
|
||||
ini_section_delete_var(cat, "ide_ter");
|
||||
|
||||
@@ -114,7 +114,7 @@ int isa_cycles, cpu_inited,
|
||||
cpu_waitstates, cpu_cache_int_enabled, cpu_cache_ext_enabled,
|
||||
cpu_isa_speed, cpu_pci_speed, cpu_isa_pci_div, cpu_agp_speed, cpu_alt_reset,
|
||||
|
||||
cpu_override, cpu_effective, cpu_multi, cpu_16bitbus, cpu_64bitbus, cpu_busspeed,
|
||||
cpu_override, cpu_effective, cpu_multi, cpu_16bitbus, cpu_64bitbus,
|
||||
cpu_cyrix_alignment, CPUID,
|
||||
|
||||
is186, is_nec,
|
||||
@@ -138,7 +138,7 @@ uint8_t _cache[2048];
|
||||
uint64_t cpu_CR4_mask, tsc = 0;
|
||||
uint64_t pmc[2] = { 0, 0 };
|
||||
|
||||
double cpu_dmulti;
|
||||
double cpu_dmulti, cpu_busspeed;
|
||||
|
||||
msr_t msr;
|
||||
|
||||
|
||||
@@ -490,10 +490,11 @@ extern int cpu_override;
|
||||
extern int cpu_isintel;
|
||||
extern int cpu_iscyrix;
|
||||
extern int cpu_16bitbus, cpu_64bitbus;
|
||||
extern int cpu_busspeed, cpu_pci_speed;
|
||||
extern int cpu_pci_speed;
|
||||
extern int cpu_multi;
|
||||
extern double cpu_dmulti;
|
||||
extern double fpu_multi;
|
||||
extern double cpu_busspeed;
|
||||
extern int cpu_cyrix_alignment; /*Cyrix 5x86/6x86 only has data misalignment
|
||||
penalties when crossing 8-byte boundaries*/
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <86box/device.h>
|
||||
#include <86box/dma.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/keyboard.h>
|
||||
#include <86box/mem.h>
|
||||
#include <86box/rom.h>
|
||||
#include <86box/nmi.h>
|
||||
@@ -265,9 +266,12 @@ reset_common(int hard)
|
||||
if (is286) {
|
||||
loadcs(0xF000);
|
||||
cpu_state.pc = 0xFFF0;
|
||||
rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF;
|
||||
if (is6117)
|
||||
rammask |= 0x03000000;
|
||||
if (hard) {
|
||||
rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF;
|
||||
if (is6117)
|
||||
rammask |= 0x03000000;
|
||||
mem_a20_key = mem_a20_alt = mem_a20_state = 0;
|
||||
}
|
||||
}
|
||||
idt.base = 0;
|
||||
cpu_state.flags = 2;
|
||||
@@ -315,6 +319,10 @@ reset_common(int hard)
|
||||
cache_index = 0;
|
||||
memset(_tr, 0x00, sizeof(_tr));
|
||||
memset(_cache, 0x00, sizeof(_cache));
|
||||
|
||||
/* If we have an AT or PS/2 keyboard controller, make sure the A20 state
|
||||
is correct. */
|
||||
kbc_at_a20_reset();
|
||||
}
|
||||
|
||||
if (!is286)
|
||||
|
||||
10
src/device.c
10
src/device.c
@@ -92,7 +92,7 @@ device_set_context(device_context_t *c, const device_t *d, int inst)
|
||||
void *sec, *single_sec;
|
||||
|
||||
memset(c, 0, sizeof(device_context_t));
|
||||
c->dev = d;
|
||||
c->dev = d;
|
||||
c->instance = inst;
|
||||
if (inst) {
|
||||
sprintf(c->name, "%s #%i", d->name, inst);
|
||||
@@ -135,7 +135,7 @@ device_context_restore(void)
|
||||
}
|
||||
|
||||
static void *
|
||||
device_add_common(const device_t *d, const device_t *cd, void *p, void* params, int inst)
|
||||
device_add_common(const device_t *d, const device_t *cd, void *p, void *params, int inst)
|
||||
{
|
||||
void *priv = NULL;
|
||||
int c;
|
||||
@@ -203,7 +203,7 @@ device_add(const device_t *d)
|
||||
}
|
||||
|
||||
void *
|
||||
device_add_parameters(const device_t *d, void* params)
|
||||
device_add_parameters(const device_t *d, void *params)
|
||||
{
|
||||
return device_add_common(d, d, NULL, params, 0);
|
||||
}
|
||||
@@ -216,7 +216,7 @@ device_add_ex(const device_t *d, void *priv)
|
||||
}
|
||||
|
||||
void
|
||||
device_add_ex_parameters(const device_t *d, void* priv, void *params)
|
||||
device_add_ex_parameters(const device_t *d, void *priv, void *params)
|
||||
{
|
||||
device_add_common(d, d, priv, params, 0);
|
||||
}
|
||||
@@ -293,7 +293,7 @@ device_cadd_inst_ex(const device_t *d, const device_t *cd, void *priv, int inst)
|
||||
}
|
||||
|
||||
void
|
||||
device_cadd_inst_ex_parameters(const device_t *d, const device_t *cd, void *priv, int inst, void* params)
|
||||
device_cadd_inst_ex_parameters(const device_t *d, const device_t *cd, void *priv, int inst, void *params)
|
||||
{
|
||||
device_add_common(d, cd, priv, params, inst);
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
#define ISARTC_A6PAK 3
|
||||
#define ISARTC_VENDEX 4
|
||||
|
||||
#define ISARTC_DEBUG 0
|
||||
#define ISARTC_DEBUG 0
|
||||
|
||||
typedef struct {
|
||||
const char *name; /* board name */
|
||||
@@ -572,7 +572,7 @@ isartc_init(const device_t *info)
|
||||
dev->f_rd, NULL, NULL, dev->f_wr, NULL, NULL, dev);
|
||||
|
||||
/* Hook into the NVR backend. */
|
||||
dev->nvr.fn = (char *)info->internal_name;
|
||||
dev->nvr.fn = (char *) info->internal_name;
|
||||
dev->nvr.irq = dev->irq;
|
||||
if (!is_at)
|
||||
nvr_init(&dev->nvr);
|
||||
|
||||
@@ -66,6 +66,7 @@ static uint8_t
|
||||
fake_shift_needed(uint16_t scan)
|
||||
{
|
||||
switch (scan) {
|
||||
case 0x137: /* Yes, Print Screen requires the fake shifts. */
|
||||
case 0x147:
|
||||
case 0x148:
|
||||
case 0x149:
|
||||
@@ -125,9 +126,13 @@ key_process(uint16_t scan, int down)
|
||||
void
|
||||
keyboard_input(int down, uint16_t scan)
|
||||
{
|
||||
/* Special case for E1 1D, translate it to 0100 - special case. */
|
||||
if ((scan >> 8) == 0xe1) {
|
||||
if ((scan & 0xff) == 0x1d)
|
||||
scan = 0x0100;
|
||||
/* Translate E0 xx scan codes to 01xx because we use 512-byte arrays for states
|
||||
and scan code sets. */
|
||||
if ((scan >> 8) == 0xe0) {
|
||||
} else if ((scan >> 8) == 0xe0) {
|
||||
scan &= 0x00ff;
|
||||
scan |= 0x0100; /* extended key code */
|
||||
} else if ((scan >> 8) != 0x01)
|
||||
@@ -295,11 +300,30 @@ keyboard_recv(uint16_t key)
|
||||
return recv_key[key];
|
||||
}
|
||||
|
||||
/* Do we have Control-Alt-PgDn in the keyboard buffer? */
|
||||
int
|
||||
keyboard_isfsenter(void)
|
||||
{
|
||||
return ((recv_key[0x01d] || recv_key[0x11d]) && (recv_key[0x038] || recv_key[0x138]) && (recv_key[0x049] || recv_key[0x149]));
|
||||
}
|
||||
|
||||
int
|
||||
keyboard_isfsenter_down(void)
|
||||
{
|
||||
return (!recv_key[0x01d] && !recv_key[0x11d] && !recv_key[0x038] && !recv_key[0x138] && !recv_key[0x049] && !recv_key[0x149]);
|
||||
}
|
||||
|
||||
/* Do we have Control-Alt-PgDn in the keyboard buffer? */
|
||||
int
|
||||
keyboard_isfsexit(void)
|
||||
{
|
||||
return ((recv_key[0x01D] || recv_key[0x11D]) && (recv_key[0x038] || recv_key[0x138]) && (recv_key[0x051] || recv_key[0x151]));
|
||||
return ((recv_key[0x01d] || recv_key[0x11d]) && (recv_key[0x038] || recv_key[0x138]) && (recv_key[0x051] || recv_key[0x151]));
|
||||
}
|
||||
|
||||
int
|
||||
keyboard_isfsexit_down(void)
|
||||
{
|
||||
return (!recv_key[0x01d] && !recv_key[0x11d] && !recv_key[0x038] && !recv_key[0x138] && !recv_key[0x051] && !recv_key[0x151]);
|
||||
}
|
||||
|
||||
/* Do we have F8-F12 in the keyboard buffer? */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,8 @@
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/gdbstub.h>
|
||||
#include <86box/mouse.h>
|
||||
|
||||
typedef struct {
|
||||
@@ -40,11 +42,12 @@ int mouse_x,
|
||||
mouse_buttons,
|
||||
mouse_mode,
|
||||
mouse_tablet_in_proximity = 0,
|
||||
tablet_tool_type = 1; /* 0 = Puck/Cursor, 1 = Pen */
|
||||
tablet_tool_type = 1; /* 0 = Puck/Cursor, 1 = Pen */
|
||||
|
||||
double mouse_x_abs,
|
||||
mouse_y_abs;
|
||||
mouse_y_abs;
|
||||
|
||||
pc_timer_t mouse_timer; /* mouse event timer */
|
||||
|
||||
static const device_t mouse_none_device = {
|
||||
.name = "None",
|
||||
@@ -76,19 +79,20 @@ static const device_t mouse_internal_device = {
|
||||
|
||||
static mouse_t mouse_devices[] = {
|
||||
// clang-format off
|
||||
{ &mouse_none_device },
|
||||
{ &mouse_internal_device },
|
||||
{ &mouse_logibus_device },
|
||||
{ &mouse_msinport_device },
|
||||
{ &mouse_none_device },
|
||||
{ &mouse_internal_device },
|
||||
{ &mouse_logibus_device },
|
||||
{ &mouse_msinport_device },
|
||||
#if 0
|
||||
{ &mouse_genibus_device },
|
||||
{ &mouse_genibus_device },
|
||||
#endif
|
||||
{ &mouse_mssystems_device },
|
||||
{ &mouse_msserial_device },
|
||||
{ &mouse_ltserial_device },
|
||||
{ &mouse_ps2_device },
|
||||
{ &mouse_wacom_device },
|
||||
{ NULL }
|
||||
{ &mouse_mssystems_device },
|
||||
{ &mouse_msserial_device },
|
||||
{ &mouse_ltserial_device },
|
||||
{ &mouse_ps2_device },
|
||||
{ &mouse_wacom_device },
|
||||
{ &mouse_wacom_artpad_device },
|
||||
{ NULL }
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
@@ -141,6 +145,20 @@ mouse_close(void)
|
||||
mouse_priv = NULL;
|
||||
mouse_nbut = 0;
|
||||
mouse_dev_poll = NULL;
|
||||
|
||||
timer_stop(&mouse_timer);
|
||||
}
|
||||
|
||||
static void
|
||||
mouse_timer_poll(void *priv)
|
||||
{
|
||||
/* Poll at 255 Hz, maximum supported by PS/2 mic. */
|
||||
timer_on_auto(&mouse_timer, 1000000.0 / 255.0);
|
||||
|
||||
#ifdef USE_GDBSTUB /* avoid a KBC FIFO overflow when CPU emulation is stalled */
|
||||
if (gdbstub_step == GDBSTUB_EXEC)
|
||||
#endif
|
||||
mouse_process();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -165,6 +183,11 @@ mouse_reset(void)
|
||||
|
||||
if (mouse_curr != NULL)
|
||||
mouse_priv = device_add(mouse_curr);
|
||||
|
||||
timer_add(&mouse_timer, mouse_timer_poll, NULL, 0);
|
||||
|
||||
/* Poll at 255 Hz, maximum supported by PS/2 mic. */
|
||||
timer_on_auto(&mouse_timer, 1000000.0 / 255.0);
|
||||
}
|
||||
|
||||
/* Callback from the hardware driver. */
|
||||
|
||||
@@ -82,18 +82,27 @@ mouse_clear_data(void *priv)
|
||||
}
|
||||
|
||||
static void
|
||||
ps2_report_coordinates(mouse_t *dev)
|
||||
ps2_report_coordinates(mouse_t *dev, int cmd)
|
||||
{
|
||||
uint8_t buff[3] = { 0x08, 0x00, 0x00 };
|
||||
int temp_z;
|
||||
|
||||
if (dev->x > 255)
|
||||
if (dev->x > 255) {
|
||||
dev->x = 255;
|
||||
if (dev->x < -256)
|
||||
buff[0] |= 0x40;
|
||||
}
|
||||
if (dev->x < -256) {
|
||||
dev->x = -256;
|
||||
if (dev->y > 255)
|
||||
buff[0] |= 0x40;
|
||||
}
|
||||
if (dev->y > 255) {
|
||||
dev->y = 255;
|
||||
if (dev->y < -256)
|
||||
buff[0] |= 0x80;
|
||||
}
|
||||
if (dev->y < -256) {
|
||||
dev->y = -256;
|
||||
buff[0] |= 0x80;
|
||||
}
|
||||
if (dev->z < -8)
|
||||
dev->z = -8;
|
||||
if (dev->z > 7)
|
||||
@@ -114,19 +123,31 @@ ps2_report_coordinates(mouse_t *dev)
|
||||
buff[1] = (dev->x & 0xff);
|
||||
buff[2] = (dev->y & 0xff);
|
||||
|
||||
keyboard_at_adddata_mouse(buff[0]);
|
||||
keyboard_at_adddata_mouse(buff[1]);
|
||||
keyboard_at_adddata_mouse(buff[2]);
|
||||
if (cmd) {
|
||||
keyboard_at_adddata_mouse_cmd(buff[0]);
|
||||
keyboard_at_adddata_mouse_cmd(buff[1]);
|
||||
keyboard_at_adddata_mouse_cmd(buff[2]);
|
||||
} else {
|
||||
keyboard_at_adddata_mouse(buff[0]);
|
||||
keyboard_at_adddata_mouse(buff[1]);
|
||||
keyboard_at_adddata_mouse(buff[2]);
|
||||
}
|
||||
if (dev->flags & FLAG_INTMODE) {
|
||||
int temp_z = dev->z;
|
||||
temp_z = dev->z & 0x0f;
|
||||
if ((dev->flags & FLAG_5BTN)) {
|
||||
temp_z &= 0xF;
|
||||
if (mouse_buttons & 8)
|
||||
temp_z |= 0x10;
|
||||
if (mouse_buttons & 16)
|
||||
temp_z |= 0x20;
|
||||
} else {
|
||||
/* The wheel coordinate is sign-extended. */
|
||||
if (temp_z & 0x08)
|
||||
temp_z |= 0xf0;
|
||||
}
|
||||
keyboard_at_adddata_mouse(temp_z);
|
||||
if (cmd)
|
||||
keyboard_at_adddata_mouse_cmd(temp_z);
|
||||
else
|
||||
keyboard_at_adddata_mouse(temp_z);
|
||||
}
|
||||
|
||||
dev->x = dev->y = dev->z = 0;
|
||||
@@ -147,16 +168,16 @@ ps2_write(uint8_t val, void *priv)
|
||||
switch (dev->command) {
|
||||
case 0xe8: /* set mouse resolution */
|
||||
dev->resolution = val;
|
||||
keyboard_at_adddata_mouse(0xfa);
|
||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
||||
break;
|
||||
|
||||
case 0xf3: /* set sample rate */
|
||||
dev->sample_rate = val;
|
||||
keyboard_at_adddata_mouse(0xfa); /* Command response */
|
||||
keyboard_at_adddata_mouse_cmd(0xfa); /* Command response */
|
||||
break;
|
||||
|
||||
default:
|
||||
keyboard_at_adddata_mouse(0xfc);
|
||||
keyboard_at_adddata_mouse_cmd(0xfc);
|
||||
}
|
||||
} else {
|
||||
dev->command = val;
|
||||
@@ -164,21 +185,21 @@ ps2_write(uint8_t val, void *priv)
|
||||
switch (dev->command) {
|
||||
case 0xe6: /* set scaling to 1:1 */
|
||||
dev->flags &= ~FLAG_SCALED;
|
||||
keyboard_at_adddata_mouse(0xfa);
|
||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
||||
break;
|
||||
|
||||
case 0xe7: /* set scaling to 2:1 */
|
||||
dev->flags |= FLAG_SCALED;
|
||||
keyboard_at_adddata_mouse(0xfa);
|
||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
||||
break;
|
||||
|
||||
case 0xe8: /* set mouse resolution */
|
||||
dev->flags |= FLAG_CTRLDAT;
|
||||
keyboard_at_adddata_mouse(0xfa);
|
||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
||||
break;
|
||||
|
||||
case 0xe9: /* status request */
|
||||
keyboard_at_adddata_mouse(0xfa);
|
||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
||||
temp = (dev->flags & 0x30);
|
||||
if (mouse_buttons & 1)
|
||||
temp |= 4;
|
||||
@@ -186,46 +207,46 @@ ps2_write(uint8_t val, void *priv)
|
||||
temp |= 1;
|
||||
if ((mouse_buttons & 4) && (dev->flags & FLAG_INTELLI))
|
||||
temp |= 2;
|
||||
keyboard_at_adddata_mouse(temp);
|
||||
keyboard_at_adddata_mouse(dev->resolution);
|
||||
keyboard_at_adddata_mouse(dev->sample_rate);
|
||||
keyboard_at_adddata_mouse_cmd(temp);
|
||||
keyboard_at_adddata_mouse_cmd(dev->resolution);
|
||||
keyboard_at_adddata_mouse_cmd(dev->sample_rate);
|
||||
break;
|
||||
|
||||
case 0xea: /* set stream */
|
||||
dev->flags &= ~FLAG_CTRLDAT;
|
||||
mouse_scan = 1;
|
||||
keyboard_at_adddata_mouse(0xfa); /* ACK for command byte */
|
||||
keyboard_at_adddata_mouse_cmd(0xfa); /* ACK for command byte */
|
||||
break;
|
||||
|
||||
case 0xeb: /* Get mouse data */
|
||||
keyboard_at_adddata_mouse(0xfa);
|
||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
||||
|
||||
ps2_report_coordinates(dev);
|
||||
ps2_report_coordinates(dev, 1);
|
||||
break;
|
||||
|
||||
case 0xf2: /* read ID */
|
||||
keyboard_at_adddata_mouse(0xfa);
|
||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
||||
if (dev->flags & FLAG_INTMODE)
|
||||
keyboard_at_adddata_mouse((dev->flags & FLAG_5BTN) ? 0x04 : 0x03);
|
||||
keyboard_at_adddata_mouse_cmd((dev->flags & FLAG_5BTN) ? 0x04 : 0x03);
|
||||
else
|
||||
keyboard_at_adddata_mouse(0x00);
|
||||
keyboard_at_adddata_mouse_cmd(0x00);
|
||||
break;
|
||||
|
||||
case 0xf3: /* set command mode */
|
||||
dev->flags |= FLAG_CTRLDAT;
|
||||
keyboard_at_adddata_mouse(0xfa); /* ACK for command byte */
|
||||
keyboard_at_adddata_mouse_cmd(0xfa); /* ACK for command byte */
|
||||
break;
|
||||
|
||||
case 0xf4: /* enable */
|
||||
dev->flags |= FLAG_ENABLED;
|
||||
mouse_scan = 1;
|
||||
keyboard_at_adddata_mouse(0xfa);
|
||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
||||
break;
|
||||
|
||||
case 0xf5: /* disable */
|
||||
dev->flags &= ~FLAG_ENABLED;
|
||||
mouse_scan = 0;
|
||||
keyboard_at_adddata_mouse(0xfa);
|
||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
||||
break;
|
||||
|
||||
case 0xf6: /* set defaults */
|
||||
@@ -235,15 +256,15 @@ mouse_reset:
|
||||
dev->flags &= 0x88;
|
||||
mouse_scan = 1;
|
||||
keyboard_at_mouse_reset();
|
||||
keyboard_at_adddata_mouse(0xfa);
|
||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
||||
if (dev->command == 0xff) {
|
||||
keyboard_at_adddata_mouse(0xaa);
|
||||
keyboard_at_adddata_mouse(0x00);
|
||||
keyboard_at_adddata_mouse_cmd(0xaa);
|
||||
keyboard_at_adddata_mouse_cmd(0x00);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
keyboard_at_adddata_mouse(0xfe);
|
||||
keyboard_at_adddata_mouse_cmd(0xfe);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,16 +274,15 @@ mouse_reset:
|
||||
|
||||
dev->last_data[5] = val;
|
||||
|
||||
if (dev->last_data[0] == 0xf3 && dev->last_data[1] == 0xc8
|
||||
&& dev->last_data[2] == 0xf3 && dev->last_data[3] == 0xc8
|
||||
&& dev->last_data[4] == 0xf3 && dev->last_data[5] == 0x50
|
||||
&& mouse_get_buttons() == 5) {
|
||||
dev->flags |= FLAG_INTMODE | FLAG_5BTN;
|
||||
} else if (dev->last_data[0] == 0xf3 && dev->last_data[1] == 0xc8
|
||||
&& dev->last_data[2] == 0xf3 && dev->last_data[3] == 0x64
|
||||
&& dev->last_data[4] == 0xf3 && dev->last_data[5] == 0x50) {
|
||||
if ((dev->last_data[0] == 0xf3) && (dev->last_data[1] == 0xc8) &&
|
||||
(dev->last_data[2] == 0xf3) && (dev->last_data[3] == 0x64) &&
|
||||
(dev->last_data[4] == 0xf3) && (dev->last_data[5] == 0x50))
|
||||
dev->flags |= FLAG_INTMODE;
|
||||
}
|
||||
|
||||
if ((dev->flags & FLAG_INTMODE) && (dev->last_data[0] == 0xf3) && (dev->last_data[1] == 0xc8) &&
|
||||
(dev->last_data[2] == 0xf3) && (dev->last_data[3] == 0xc8) &&
|
||||
(dev->last_data[4] == 0xf3) && (dev->last_data[5] == 0x50))
|
||||
dev->flags |= FLAG_5BTN;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,10 +305,14 @@ ps2_poll(int x, int y, int z, int b, double abs_x, double abs_y, void *priv)
|
||||
dev->x += x;
|
||||
dev->y -= y;
|
||||
dev->z -= z;
|
||||
#if 0
|
||||
if ((dev->mode == MODE_STREAM) && (dev->flags & FLAG_ENABLED) && (keyboard_at_mouse_pos() < 13)) {
|
||||
#else
|
||||
if ((dev->mode == MODE_STREAM) && (keyboard_at_mouse_pos() < 13)) {
|
||||
#endif
|
||||
dev->b = b;
|
||||
|
||||
ps2_report_coordinates(dev);
|
||||
ps2_report_coordinates(dev, 0);
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
@@ -511,7 +511,7 @@ sermouse_command_timer(void *priv)
|
||||
}
|
||||
|
||||
static int
|
||||
sermouse_poll(int x, int y, int z, int b, double abs_x, double abs_y, void *priv)
|
||||
sermouse_poll(int x, int y, int z, int b, double abs_x, double abs_y, void *priv)
|
||||
{
|
||||
mouse_t *dev = (mouse_t *) priv;
|
||||
|
||||
|
||||
@@ -9,45 +9,123 @@
|
||||
#include <86box/mouse.h>
|
||||
#include <86box/serial.h>
|
||||
#include <86box/plat.h>
|
||||
#include <86box/fifo8.h>
|
||||
|
||||
#define FLAG_3BTN 0x20 /* enable 3-button mode */
|
||||
#define FLAG_3BTN 0x20 /* enable 3-button mode */
|
||||
|
||||
enum wacom_modes
|
||||
{
|
||||
enum wacom_modes {
|
||||
WACOM_MODE_SUPPRESSED = 0,
|
||||
WACOM_MODE_POINT = 1,
|
||||
WACOM_MODE_STREAM = 2,
|
||||
WACOM_MODE_SWITCH = 3,
|
||||
};
|
||||
|
||||
enum wacom_handshake_modes {
|
||||
WACOM_HANDSHAKE_NONE = 0,
|
||||
WACOM_HANDSHAKE_CTS = 1,
|
||||
WACOM_HANDSHAKE_DTS = 2,
|
||||
WACOM_HANDSHAKE_BOTH = 3,
|
||||
};
|
||||
|
||||
enum wacom_cmd_set {
|
||||
WACOM_CMDSET_BITPAD = 0,
|
||||
WACOM_CMDSET_MM1201 = 1,
|
||||
WACOM_CMDSET_IIS = 2,
|
||||
WACOM_CMDSET_IV = 3
|
||||
};
|
||||
|
||||
enum wacom_tablet_type {
|
||||
WACOM_TYPE_IISONLY = 0,
|
||||
WACOM_TYPE_IV,
|
||||
};
|
||||
|
||||
enum {
|
||||
REPORT_PHASE_PREPARE,
|
||||
REPORT_PHASE_TRANSMIT
|
||||
};
|
||||
|
||||
typedef struct wacom_tablet_id {
|
||||
char id[64];
|
||||
int type;
|
||||
} wacom_tablet_id;
|
||||
|
||||
static const wacom_tablet_id sd510_id = {
|
||||
.id = "~#SD51C V3.2.1.01\r",
|
||||
.type = WACOM_TYPE_IISONLY
|
||||
};
|
||||
|
||||
static const wacom_tablet_id artpad_id = {
|
||||
.id = "~#KT-0405-R00 V1.1-0\r",
|
||||
.type = WACOM_TYPE_IV
|
||||
};
|
||||
|
||||
static const uint32_t wacom_resolution_values[4] = {
|
||||
500,
|
||||
508,
|
||||
1000,
|
||||
1270
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const char *name; /* name of this device */
|
||||
int8_t type, /* type of this device */
|
||||
port;
|
||||
uint8_t flags, but, /* device flags */
|
||||
status, format,
|
||||
data_len, data[64],
|
||||
status, bits,
|
||||
data_rec[0x200];
|
||||
int abs_x, abs_y,
|
||||
rel_x, rel_y,
|
||||
oldb, b;
|
||||
|
||||
int data_pos, data_rec_pos, mode, transmission_ongoing, transmission_format, interval;
|
||||
|
||||
Fifo8 data;
|
||||
|
||||
int data_rec_pos, mode, interval;
|
||||
int increment, suppressed_increment;
|
||||
int transmission_stopped;
|
||||
int reset;
|
||||
int transmit_id, transmit_id_pending;
|
||||
int pressure_mode;
|
||||
int suppressed, measurement, always_report;
|
||||
int remote_req, remote_mode;
|
||||
int suppressed, measurement;
|
||||
int remote_req;
|
||||
|
||||
uint32_t x_res, y_res;
|
||||
const wacom_tablet_id* tablet_type;
|
||||
|
||||
int last_abs_x, last_abs_y; /* Suppressed/Increment Mode. */
|
||||
uint32_t settings; /* Settings DWORD */
|
||||
union {
|
||||
uint32_t settings; /* Settings DWORD */
|
||||
/* We don't target any architectures except x86/x64/ARM32/ARM64.
|
||||
(The ABIs for those are explicit in little-endian bit ordering) */
|
||||
struct {
|
||||
uint8_t remote_mode : 1;
|
||||
uint8_t bitpad_two_cursor_data : 1;
|
||||
uint8_t mm961_orientation : 1;
|
||||
uint8_t mm_command_set : 1;
|
||||
uint8_t tilt : 1;
|
||||
uint8_t multi_device : 1;
|
||||
uint8_t reading_height : 1;
|
||||
uint8_t pressure_sensitivity : 1;
|
||||
|
||||
uint8_t pnp : 1; /* Unused. */
|
||||
uint8_t dummy : 1;
|
||||
uint8_t terminator : 2;
|
||||
uint8_t out_of_range_data : 1;
|
||||
uint8_t origin_location : 1;
|
||||
uint8_t resolution : 2;
|
||||
|
||||
uint8_t transfer_rate : 2;
|
||||
uint8_t coord_sys : 1;
|
||||
uint8_t output_format : 1;
|
||||
uint8_t transfer_mode : 2;
|
||||
uint8_t handshake : 2;
|
||||
|
||||
uint8_t stop_bits_conf : 1;
|
||||
uint8_t data_bits_conf : 1;
|
||||
uint8_t parity : 2;
|
||||
uint8_t baud_rate : 2;
|
||||
uint8_t cmd_set : 2;
|
||||
} settings_bits;
|
||||
};
|
||||
|
||||
double transmit_period;
|
||||
double old_tsc, reset_tsc;
|
||||
@@ -56,12 +134,22 @@ typedef struct {
|
||||
serial_t *serial;
|
||||
} mouse_wacom_t;
|
||||
|
||||
static unsigned int
|
||||
reverse(register unsigned int x)
|
||||
{
|
||||
x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
|
||||
x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
|
||||
x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
|
||||
x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
|
||||
return ((x >> 16) | (x << 16));
|
||||
}
|
||||
|
||||
static double
|
||||
wacom_transmit_period(mouse_wacom_t *dev, int bps, int rps)
|
||||
{
|
||||
double dbps = (double) bps;
|
||||
double temp = 0.0;
|
||||
int word_len = 10;
|
||||
double dbps = (double) bps;
|
||||
double temp = 0.0;
|
||||
int word_len = dev->bits;
|
||||
|
||||
if (rps == -1)
|
||||
temp = (double) word_len;
|
||||
@@ -76,32 +164,105 @@ wacom_transmit_period(mouse_wacom_t *dev, int bps, int rps)
|
||||
}
|
||||
|
||||
static void
|
||||
wacom_reset(mouse_wacom_t* wacom)
|
||||
wacom_process_settings_dword(mouse_wacom_t *wacom, uint32_t dword)
|
||||
{
|
||||
wacom->transmit_period = wacom_transmit_period(wacom, 9600, -1);
|
||||
wacom->mode = WACOM_MODE_POINT;
|
||||
wacom->data_pos = 0;
|
||||
wacom->transmission_ongoing = 0;
|
||||
wacom->mode = 0;
|
||||
wacom->transmission_stopped = 0;
|
||||
wacom->interval = 0;
|
||||
wacom->transmit_id = 0;
|
||||
wacom->format = 0; /* ASCII */
|
||||
wacom->measurement = 1;
|
||||
wacom->increment = wacom->suppressed_increment = 0;
|
||||
wacom->reset_tsc = tsc;
|
||||
wacom->remote_mode = wacom->remote_req = 0;
|
||||
wacom->always_report = 0;
|
||||
wacom->settings = dword;
|
||||
|
||||
wacom->mode = wacom->settings_bits.transfer_mode;
|
||||
|
||||
wacom->bits = 1 + 7 + wacom->settings_bits.data_bits_conf;
|
||||
wacom->bits += 1 + wacom->settings_bits.stop_bits_conf;
|
||||
if (wacom->settings_bits.parity == 2 && !(wacom->bits % 2)) {
|
||||
wacom->bits++;
|
||||
} else if (wacom->settings_bits.parity == 3 && (wacom->bits % 2)) {
|
||||
wacom->bits++;
|
||||
}
|
||||
|
||||
switch(wacom->settings_bits.baud_rate) {
|
||||
case 0:
|
||||
wacom->transmit_period = wacom_transmit_period(wacom, 2400, -1);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
wacom->transmit_period = wacom_transmit_period(wacom, 4800, -1);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
wacom->transmit_period = wacom_transmit_period(wacom, 9600, -1);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
wacom->transmit_period = wacom_transmit_period(wacom, 19200, -1);
|
||||
break;
|
||||
}
|
||||
|
||||
mouse_mode = !wacom->settings_bits.coord_sys;
|
||||
wacom->x_res = wacom->y_res = wacom_resolution_values[wacom->settings_bits.resolution];
|
||||
}
|
||||
|
||||
static void
|
||||
wacom_reset(mouse_wacom_t *wacom)
|
||||
{
|
||||
wacom->transmit_period = wacom_transmit_period(wacom, 9600, -1);
|
||||
wacom->mode = WACOM_MODE_POINT;
|
||||
wacom->transmission_stopped = 0;
|
||||
wacom->interval = 0;
|
||||
wacom->transmit_id = 0;
|
||||
wacom->settings_bits.output_format = 1; /* ASCII */
|
||||
wacom->settings_bits.cmd_set = 1;
|
||||
wacom->measurement = 1;
|
||||
wacom->increment = wacom->suppressed_increment = 0;
|
||||
wacom->reset_tsc = tsc;
|
||||
wacom->settings_bits.remote_mode = wacom->remote_req = 0;
|
||||
wacom->settings_bits.out_of_range_data = 0;
|
||||
|
||||
mouse_mode = 1;
|
||||
wacom_process_settings_dword(wacom, 0xA21BC800);
|
||||
}
|
||||
|
||||
static void
|
||||
wacom_reset_artpad(mouse_wacom_t *wacom)
|
||||
{
|
||||
wacom->transmit_period = wacom_transmit_period(wacom, 9600, -1);
|
||||
wacom->mode = WACOM_MODE_SUPPRESSED;
|
||||
wacom->transmission_stopped = 0;
|
||||
wacom->interval = 0;
|
||||
wacom->transmit_id = 0;
|
||||
wacom->settings_bits.output_format = 0; /* Binary */
|
||||
wacom->measurement = 1;
|
||||
wacom->increment = 0;
|
||||
wacom->suppressed_increment = 1;
|
||||
wacom->reset_tsc = tsc;
|
||||
wacom->settings_bits.remote_mode = 0;
|
||||
wacom->remote_req = 0;
|
||||
wacom->settings_bits.out_of_range_data = 0;
|
||||
|
||||
wacom_process_settings_dword(wacom, 0xE203C000);
|
||||
mouse_mode = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
wacom_callback(struct serial_s *serial, void *priv)
|
||||
{
|
||||
mouse_wacom_t* wacom = (mouse_wacom_t*)priv;
|
||||
mouse_wacom_t *wacom = (mouse_wacom_t *) priv;
|
||||
|
||||
wacom->transmit_period = wacom_transmit_period(wacom, 9600, -1);
|
||||
switch(wacom->settings_bits.baud_rate) {
|
||||
case 0:
|
||||
wacom->transmit_period = wacom_transmit_period(wacom, 2400, -1);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
wacom->transmit_period = wacom_transmit_period(wacom, 4800, -1);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
wacom->transmit_period = wacom_transmit_period(wacom, 9600, -1);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
wacom->transmit_period = wacom_transmit_period(wacom, 19200, -1);
|
||||
break;
|
||||
}
|
||||
timer_stop(&wacom->report_timer);
|
||||
timer_on_auto(&wacom->report_timer, wacom->transmit_period);
|
||||
}
|
||||
@@ -109,8 +270,8 @@ wacom_callback(struct serial_s *serial, void *priv)
|
||||
static void
|
||||
wacom_write(struct serial_s *serial, void *priv, uint8_t data)
|
||||
{
|
||||
mouse_wacom_t* wacom = (mouse_wacom_t*)priv;
|
||||
static int special_command = 0;
|
||||
mouse_wacom_t *wacom = (mouse_wacom_t *) priv;
|
||||
static int special_command = 0;
|
||||
|
||||
if (data == '~') {
|
||||
special_command = 1;
|
||||
@@ -119,18 +280,34 @@ wacom_write(struct serial_s *serial, void *priv, uint8_t data)
|
||||
if (special_command) {
|
||||
switch (data) {
|
||||
case '#':
|
||||
{
|
||||
if (!wacom->transmission_ongoing) wacom->transmit_id++;
|
||||
break;
|
||||
}
|
||||
{
|
||||
wacom->transmit_id = 1;
|
||||
break;
|
||||
}
|
||||
case 'C':
|
||||
case '*':
|
||||
case 'R':
|
||||
{
|
||||
wacom->data_rec[wacom->data_rec_pos++] = '~';
|
||||
wacom->data_rec[wacom->data_rec_pos++] = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
special_command = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (data == '@') {
|
||||
wacom->remote_req = 1;
|
||||
wacom->remote_mode = 1;
|
||||
wacom->remote_req = 1;
|
||||
wacom->settings_bits.remote_mode = 1;
|
||||
return;
|
||||
}
|
||||
if (data == '#' && wacom->tablet_type->type == WACOM_TYPE_IV) {
|
||||
wacom_reset_artpad(wacom);
|
||||
return;
|
||||
}
|
||||
if (data == '$') {
|
||||
wacom_reset(wacom);
|
||||
return;
|
||||
}
|
||||
if (data == 0x13) {
|
||||
@@ -139,48 +316,84 @@ wacom_write(struct serial_s *serial, void *priv, uint8_t data)
|
||||
}
|
||||
if (data == 0x11) {
|
||||
wacom->transmission_stopped = 0;
|
||||
wacom->remote_mode = wacom->remote_req = 0;
|
||||
wacom->settings_bits.remote_mode = wacom->remote_req = 0;
|
||||
return;
|
||||
}
|
||||
wacom->data_rec[wacom->data_rec_pos++] = data;
|
||||
if (data == '\r' || data == '\n') {
|
||||
wacom->data_rec[wacom->data_rec_pos] = 0;
|
||||
wacom->data_rec_pos = 0;
|
||||
wacom->data_rec[wacom->data_rec_pos] = 0;
|
||||
wacom->data_rec_pos = 0;
|
||||
|
||||
if (data == '\n') pclog("Wacom: written %s", wacom->data_rec);
|
||||
else pclog("Wacom: written %s\n", wacom->data_rec);
|
||||
if (!memcmp(wacom->data_rec, "AS", 2)) {
|
||||
wacom->format = (wacom->data_rec[2] == '1');
|
||||
wacom->transmission_ongoing = 0;
|
||||
if (data == '\n')
|
||||
pclog("Wacom: written %s", wacom->data_rec);
|
||||
else
|
||||
pclog("Wacom: written %s\n", wacom->data_rec);
|
||||
if (!memcmp(wacom->data_rec, "AS", 2) && wacom->settings_bits.cmd_set == WACOM_CMDSET_IIS) {
|
||||
wacom->settings_bits.output_format = !(wacom->data_rec[2] == '1');
|
||||
} else if (!memcmp(wacom->data_rec, "SR", 2)) {
|
||||
wacom->mode = WACOM_MODE_STREAM;
|
||||
wacom->suppressed_increment = 0;
|
||||
wacom->mode = WACOM_MODE_STREAM;
|
||||
} else if (!memcmp(wacom->data_rec, "IN", 2)) {
|
||||
sscanf((const char*)wacom->data_rec, "IN%d", &wacom->increment);
|
||||
} else if (!memcmp(wacom->data_rec, "RE", 2) || wacom->data_rec[0] == '$' || wacom->data_rec[0] == '#') {
|
||||
wacom_reset(wacom);
|
||||
sscanf((const char *) wacom->data_rec, "IN%d", &wacom->increment);
|
||||
} else if (!memcmp(wacom->data_rec, "RE", 2)) {
|
||||
if (wacom->tablet_type->type == WACOM_TYPE_IV) wacom_reset_artpad(wacom);
|
||||
else wacom_reset(wacom);
|
||||
} else if (!memcmp(wacom->data_rec, "IT", 2)) {
|
||||
sscanf((const char*)wacom->data_rec, "IT%d", &wacom->interval);
|
||||
} else if (!memcmp(wacom->data_rec, "DE", 2)) {
|
||||
sscanf((const char*)wacom->data_rec, "DE%d", &mouse_mode);
|
||||
sscanf((const char *) wacom->data_rec, "IT%d", &wacom->interval);
|
||||
} else if (!memcmp(wacom->data_rec, "DE", 2) && wacom->settings_bits.cmd_set == WACOM_CMDSET_IIS) {
|
||||
sscanf((const char *) wacom->data_rec, "DE%d", &mouse_mode);
|
||||
mouse_mode = !mouse_mode;
|
||||
plat_mouse_capture(0);
|
||||
} else if (!memcmp(wacom->data_rec, "SU", 2)) {
|
||||
sscanf((const char*)wacom->data_rec, "SU%d", &wacom->suppressed_increment);
|
||||
} else if (!memcmp(wacom->data_rec, "PH", 2)) {
|
||||
sscanf((const char*)wacom->data_rec, "PH%d", &wacom->pressure_mode);
|
||||
sscanf((const char *) wacom->data_rec, "SU%d", &wacom->suppressed_increment);
|
||||
wacom->settings_bits.transfer_mode = wacom->mode = WACOM_MODE_SUPPRESSED;
|
||||
} else if (!memcmp(wacom->data_rec, "PH", 2) && wacom->settings_bits.cmd_set == WACOM_CMDSET_IIS) {
|
||||
sscanf((const char *) wacom->data_rec, "PH%d", &wacom->pressure_mode);
|
||||
} else if (!memcmp(wacom->data_rec, "IC", 2)) {
|
||||
sscanf((const char*)wacom->data_rec, "IC%d", &wacom->measurement);
|
||||
sscanf((const char *) wacom->data_rec, "IC%d", &wacom->measurement);
|
||||
} else if (!memcmp(wacom->data_rec, "SW", 2)) {
|
||||
wacom->mode = WACOM_MODE_SWITCH;
|
||||
} else if (!memcmp(wacom->data_rec, "AL", 2)) {
|
||||
sscanf((const char*)wacom->data_rec, "AL%d", &wacom->always_report);
|
||||
uint8_t out_of_range_data = wacom->settings_bits.out_of_range_data;
|
||||
wacom->settings_bits.out_of_range_data = !!out_of_range_data;
|
||||
} else if (!memcmp(wacom->data_rec, "RQ", 2)) {
|
||||
sscanf((const char*)wacom->data_rec, "RQ%d", &wacom->remote_mode);
|
||||
if (wacom->remote_mode) wacom->remote_req = 1;
|
||||
uint8_t remote_mode = 0;
|
||||
sscanf((const char *) wacom->data_rec, "RQ%d", &remote_mode);
|
||||
wacom->settings_bits.remote_mode = !!remote_mode;
|
||||
if (wacom->settings_bits.remote_mode)
|
||||
wacom->remote_req = 1;
|
||||
} else if (!memcmp(wacom->data_rec, "SP", 2)) {
|
||||
wacom->transmission_stopped = 1;
|
||||
} else if (!memcmp(wacom->data_rec, "ST", 2)){
|
||||
} else if (!memcmp(wacom->data_rec, "ST", 2)) {
|
||||
wacom->transmission_stopped = 0;
|
||||
wacom->remote_mode = wacom->remote_req = 0;
|
||||
wacom->settings_bits.remote_mode = wacom->remote_req = 0;
|
||||
} else if (!memcmp(wacom->data_rec, "NR", 2)) {
|
||||
sscanf((const char *) wacom->data_rec, "NR%d", &wacom->x_res);
|
||||
wacom->y_res = wacom->x_res;
|
||||
} else if (wacom->tablet_type->type == WACOM_TYPE_IV && wacom->data_rec[0] == '~') {
|
||||
if (!memcmp(wacom->data_rec, "~*", 2)) {
|
||||
uint32_t settings_dword = wacom->settings;
|
||||
if (strstr(wacom->data_rec, ",")) {
|
||||
uint32_t x_res = wacom->x_res, y_res = wacom->y_res;
|
||||
uint32_t increment = wacom->increment;
|
||||
uint32_t interval = wacom->interval;
|
||||
|
||||
sscanf("~*%08X,%d,%d,%d,%d", wacom->data_rec, &settings_dword, &increment, &interval, &x_res, &y_res);
|
||||
|
||||
wacom->interval = interval;
|
||||
wacom->increment = increment;
|
||||
wacom->x_res = x_res;
|
||||
wacom->y_res = y_res;
|
||||
} else {
|
||||
sscanf("~*%X", wacom->data_rec, &settings_dword);
|
||||
}
|
||||
wacom_process_settings_dword(wacom, settings_dword);
|
||||
} else if (!memcmp(wacom->data_rec, "~C", 2)) {
|
||||
fifo8_push_all(&wacom->data, "~C5039,3779\r", sizeof("~C5039,3779\r") - 1);
|
||||
} else if (!memcmp(wacom->data_rec, "~R", 2)) {
|
||||
uint8_t data[256] = { 0 };
|
||||
snprintf(data, sizeof(data), "~*%08X,%d,%d,%d,%d\r", wacom->settings, wacom->increment, wacom->interval, wacom->x_res, wacom->y_res);
|
||||
fifo8_push_all(&wacom->data, data, strlen(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,16 +401,27 @@ wacom_write(struct serial_s *serial, void *priv, uint8_t data)
|
||||
static int
|
||||
wacom_poll(int x, int y, int z, int b, double abs_x, double abs_y, void *priv)
|
||||
{
|
||||
mouse_wacom_t* wacom = (mouse_wacom_t*)priv;
|
||||
wacom->abs_x = abs_x * (wacom->measurement ? 4566. : 5800.);
|
||||
wacom->abs_y = abs_y * (wacom->measurement ? 2972. : 3774.);
|
||||
if (wacom->abs_x > (wacom->measurement ? 4566 : 5800)) wacom->abs_x = (wacom->measurement ? 4566 : 5800);
|
||||
if (wacom->abs_y > (wacom->measurement ? 2972 : 3774)) wacom->abs_x = (wacom->measurement ? 2972 : 3774);
|
||||
if (wacom->abs_x < 0) wacom->abs_x = 0;
|
||||
if (wacom->abs_y < 0) wacom->abs_y = 0;
|
||||
wacom->rel_x = x;
|
||||
wacom->rel_y = y;
|
||||
if (wacom->b != b) wacom->oldb = wacom->b;
|
||||
mouse_wacom_t *wacom = (mouse_wacom_t *) priv;
|
||||
|
||||
if (wacom->settings_bits.cmd_set == WACOM_CMDSET_IV) {
|
||||
wacom->abs_x = abs_x * 5039. * (wacom->x_res / 1000.);
|
||||
wacom->abs_y = abs_y * 3779. * (wacom->y_res / 1000.);
|
||||
} else {
|
||||
wacom->abs_x = abs_x * (wacom->measurement ? 4566. : 5800.);
|
||||
wacom->abs_y = abs_y * (wacom->measurement ? 2972. : 3774.);
|
||||
if (wacom->abs_x > (wacom->measurement ? 4566 : 5800))
|
||||
wacom->abs_x = (wacom->measurement ? 4566 : 5800);
|
||||
if (wacom->abs_y > (wacom->measurement ? 2972 : 3774))
|
||||
wacom->abs_x = (wacom->measurement ? 2972 : 3774);
|
||||
if (wacom->abs_x < 0)
|
||||
wacom->abs_x = 0;
|
||||
if (wacom->abs_y < 0)
|
||||
wacom->abs_y = 0;
|
||||
wacom->rel_x = x;
|
||||
wacom->rel_y = y;
|
||||
}
|
||||
if (wacom->b != b)
|
||||
wacom->oldb = wacom->b;
|
||||
wacom->b = b;
|
||||
return (0);
|
||||
}
|
||||
@@ -205,9 +429,12 @@ wacom_poll(int x, int y, int z, int b, double abs_x, double abs_y, void *priv)
|
||||
static int
|
||||
wacom_switch_off_to_on(int b, int oldb)
|
||||
{
|
||||
if (!(oldb & 0x1) && (b & 1)) return 1;
|
||||
if (!(oldb & 0x2) && (b & 2)) return 1;
|
||||
if (!(oldb & 0x4) && (b & 4)) return 1;
|
||||
if (!(oldb & 0x1) && (b & 1))
|
||||
return 1;
|
||||
if (!(oldb & 0x2) && (b & 2))
|
||||
return 1;
|
||||
if (!(oldb & 0x4) && (b & 4))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -215,64 +442,85 @@ wacom_switch_off_to_on(int b, int oldb)
|
||||
static uint8_t
|
||||
wacom_get_switch(int b)
|
||||
{
|
||||
if (b & 0x4) return 0x23;
|
||||
if (b & 0x2) return 0x22;
|
||||
if (b & 0x1) return 0x21;
|
||||
if (b & 0x4)
|
||||
return 0x23;
|
||||
if (b & 0x2)
|
||||
return 0x22;
|
||||
if (b & 0x1)
|
||||
return 0x21;
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
static void
|
||||
wacom_transmit_prepare(mouse_wacom_t* wacom, int x, int y)
|
||||
wacom_transmit_prepare(mouse_wacom_t *wacom, int x, int y)
|
||||
{
|
||||
wacom->transmission_ongoing = 1;
|
||||
wacom->data_pos = 0;
|
||||
memset(wacom->data, 0, sizeof(wacom->data));
|
||||
if (wacom->transmit_id) {
|
||||
wacom->transmission_format = 0;
|
||||
snprintf((char*)wacom->data, sizeof(wacom->data), "~#SD51C V3.2.1.01\r");
|
||||
uint8_t data[128] = { 0 };
|
||||
snprintf((char *) data, sizeof(data), "%s", wacom->tablet_type->id);
|
||||
fifo8_push_all(&wacom->data, data, strlen(data));
|
||||
wacom->transmit_id = 0;
|
||||
return;
|
||||
}
|
||||
wacom->transmission_format = wacom->format;
|
||||
wacom->last_abs_x = wacom->abs_x;
|
||||
wacom->last_abs_y = wacom->abs_y;
|
||||
wacom->remote_req = 0;
|
||||
wacom->last_abs_x = wacom->abs_x;
|
||||
wacom->last_abs_y = wacom->abs_y;
|
||||
wacom->remote_req = 0;
|
||||
|
||||
wacom->oldb = wacom->b;
|
||||
if (wacom->format == 1) {
|
||||
wacom->data[0] = 0xC0;
|
||||
wacom->data[6] = wacom->pressure_mode ? ((wacom->b & 0x1) ? (uint8_t)31 : (uint8_t)-31) : wacom_get_switch(wacom->b);
|
||||
if (wacom->settings_bits.output_format == 0) {
|
||||
uint8_t data[7];
|
||||
data[0] = 0xC0;
|
||||
if (wacom->settings_bits.cmd_set == WACOM_CMDSET_IV) {
|
||||
if (tablet_tool_type == 0)
|
||||
data[6] = ((wacom->b & 0x1) ? (uint8_t) 31 : (uint8_t) -1);
|
||||
else
|
||||
data[6] = ((wacom->b & 0x1) ? (uint8_t) 63 : (uint8_t) -63);
|
||||
}
|
||||
else
|
||||
data[6] = (wacom->pressure_mode || wacom->settings_bits.cmd_set == WACOM_CMDSET_IV) ? ((wacom->b & 0x1) ? (uint8_t) 31 : (uint8_t) -31) : wacom_get_switch(wacom->b);
|
||||
|
||||
wacom->data[5] = (y & 0x7F);
|
||||
wacom->data[4] = ((y & 0x3F80) >> 7) & 0x7F;
|
||||
wacom->data[3] = (((y & 0xC000) >> 14) & 3);
|
||||
data[5] = (y & 0x7F);
|
||||
data[4] = ((y & 0x3F80) >> 7) & 0x7F;
|
||||
data[3] = (((y & 0xC000) >> 14) & 3);
|
||||
|
||||
wacom->data[2] = (x & 0x7F);
|
||||
wacom->data[1] = ((x & 0x3F80) >> 7) & 0x7F;
|
||||
wacom->data[0] |= (((x & 0xC000) >> 14) & 3);
|
||||
data[2] = (x & 0x7F);
|
||||
data[1] = ((x & 0x3F80) >> 7) & 0x7F;
|
||||
data[0] |= (((x & 0xC000) >> 14) & 3);
|
||||
|
||||
if (mouse_mode == 0) {
|
||||
wacom->data[0] |= (!!(x < 0)) << 2;
|
||||
wacom->data[3] |= (!!(y < 0)) << 2;
|
||||
if (mouse_mode == 0 && wacom->settings_bits.cmd_set == WACOM_CMDSET_IIS) {
|
||||
data[0] |= (!!(x < 0)) << 2;
|
||||
data[3] |= (!!(y < 0)) << 2;
|
||||
}
|
||||
|
||||
if (wacom->pressure_mode) {
|
||||
wacom->data[0] |= 0x10;
|
||||
wacom->data[6] &= 0x7F;
|
||||
if (wacom->settings_bits.cmd_set == WACOM_CMDSET_IV) {
|
||||
data[6] &= 0x7F;
|
||||
data[3] &= 0x3;
|
||||
if (wacom_get_switch(wacom->b) != 0x21) {
|
||||
data[3] |= (wacom_get_switch(wacom->b) & 0xF) << 3;
|
||||
data[0] |= 0x8;
|
||||
}
|
||||
}
|
||||
|
||||
if (wacom->pressure_mode && wacom->settings_bits.cmd_set == WACOM_CMDSET_IIS) {
|
||||
data[0] |= 0x10;
|
||||
data[6] &= 0x7F;
|
||||
}
|
||||
|
||||
if (tablet_tool_type == 1) {
|
||||
wacom->data[0] |= 0x20;
|
||||
data[0] |= 0x20;
|
||||
}
|
||||
|
||||
|
||||
if (!mouse_tablet_in_proximity) {
|
||||
wacom->data[0] &= ~0x40;
|
||||
data[0] &= ~0x40;
|
||||
}
|
||||
fifo8_push_all(&wacom->data, data, 7);
|
||||
} else {
|
||||
wacom->data[0] = 0;
|
||||
snprintf((char*)wacom->data, sizeof(wacom->data), "*,%05d,%05d,%d\r\n",
|
||||
wacom->abs_x, wacom->abs_y,
|
||||
wacom->pressure_mode ? ((wacom->b & 0x1) ? (uint8_t)-31 : (uint8_t)15) : ((wacom->b & 0x1) ? 21 : 00));
|
||||
uint8_t data[128];
|
||||
data[0] = 0;
|
||||
snprintf((char *) data, sizeof(data), "*,%05d,%05d,%d\r\n",
|
||||
wacom->abs_x, wacom->abs_y,
|
||||
wacom->pressure_mode ? ((wacom->b & 0x1) ? (uint8_t) -31 : (uint8_t) 15) : ((wacom->b & 0x1) ? 21 : 00));
|
||||
fifo8_push_all(&wacom->data, data, strlen(data));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,57 +528,62 @@ extern double cpuclock;
|
||||
static void
|
||||
wacom_report_timer(void *priv)
|
||||
{
|
||||
mouse_wacom_t* wacom = (mouse_wacom_t*)priv;
|
||||
double milisecond_diff = ((double)(tsc - wacom->old_tsc)) / cpuclock * 1000.0;
|
||||
int relative_mode = (mouse_mode == 0);
|
||||
int x = (relative_mode ? wacom->rel_x : wacom->abs_x);
|
||||
int y = (relative_mode ? wacom->rel_y : wacom->abs_y);
|
||||
int x_diff = abs(relative_mode ? wacom->rel_x : (wacom->abs_x - wacom->last_abs_x));
|
||||
int y_diff = abs(relative_mode ? wacom->rel_y : (wacom->abs_y - wacom->last_abs_y));
|
||||
int increment = wacom->suppressed_increment ? wacom->suppressed_increment : wacom->increment;
|
||||
mouse_wacom_t *wacom = (mouse_wacom_t *) priv;
|
||||
double milisecond_diff = ((double) (tsc - wacom->old_tsc)) / cpuclock * 1000.0;
|
||||
int relative_mode = (mouse_mode == 0);
|
||||
int x = (relative_mode ? wacom->rel_x : wacom->abs_x);
|
||||
int y = (relative_mode ? wacom->rel_y : wacom->abs_y);
|
||||
int x_diff = abs(relative_mode ? wacom->rel_x : (wacom->abs_x - wacom->last_abs_x));
|
||||
int y_diff = abs(relative_mode ? wacom->rel_y : (wacom->abs_y - wacom->last_abs_y));
|
||||
int increment = wacom->suppressed_increment ? wacom->suppressed_increment : wacom->increment;
|
||||
|
||||
timer_on_auto(&wacom->report_timer, wacom->transmit_period);
|
||||
if ((((double)(tsc - wacom->reset_tsc)) / cpuclock * 1000.0) <= 10)
|
||||
if ((((double) (tsc - wacom->reset_tsc)) / cpuclock * 1000.0) <= 10)
|
||||
return;
|
||||
if (wacom->transmit_id && !wacom->transmission_ongoing)
|
||||
if (wacom->transmit_id)
|
||||
goto transmit_prepare;
|
||||
if (wacom->transmission_ongoing)
|
||||
if (fifo8_num_used(&wacom->data))
|
||||
goto transmit;
|
||||
else if (wacom->remote_mode && !wacom->remote_req)
|
||||
else if (wacom->settings_bits.remote_mode && !wacom->remote_req)
|
||||
return;
|
||||
else {
|
||||
if (wacom->remote_mode && wacom->remote_req) {
|
||||
if (wacom->settings_bits.remote_mode && wacom->remote_req) {
|
||||
goto transmit_prepare;
|
||||
}
|
||||
if (wacom->transmission_stopped || (!mouse_tablet_in_proximity && !wacom->always_report))
|
||||
if (wacom->transmission_stopped || (!mouse_tablet_in_proximity && !wacom->settings_bits.out_of_range_data))
|
||||
return;
|
||||
|
||||
if (milisecond_diff >= (wacom->interval * 5)) {
|
||||
wacom->old_tsc = tsc;
|
||||
} else
|
||||
return;
|
||||
|
||||
|
||||
switch (wacom->mode) {
|
||||
case WACOM_MODE_STREAM:
|
||||
default:
|
||||
break;
|
||||
|
||||
|
||||
case WACOM_MODE_POINT:
|
||||
{
|
||||
if (!(wacom_switch_off_to_on(wacom->b, wacom->oldb)))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
{
|
||||
if (wacom->suppressed_increment)
|
||||
break;
|
||||
if (!(wacom_switch_off_to_on(wacom->b, wacom->oldb)))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
case WACOM_MODE_SWITCH:
|
||||
{
|
||||
if (!wacom->b)
|
||||
return;
|
||||
|
||||
break;
|
||||
}
|
||||
{
|
||||
if (!wacom->b)
|
||||
return;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (increment && !mouse_tablet_in_proximity)
|
||||
return;
|
||||
|
||||
if (increment && !(x_diff > increment || y_diff > increment)) {
|
||||
if (wacom->suppressed_increment && (wacom->b == wacom->oldb))
|
||||
return;
|
||||
@@ -344,13 +597,9 @@ transmit_prepare:
|
||||
wacom_transmit_prepare(wacom, x, y);
|
||||
|
||||
transmit:
|
||||
serial_write_fifo(wacom->serial, wacom->data[wacom->data_pos++]);
|
||||
if ((wacom->transmission_format == 0 && wacom->data[wacom->data_pos] == 0)
|
||||
|| (wacom->transmission_format == 1 && wacom->data_pos == 7)) {
|
||||
wacom->transmission_ongoing = 0;
|
||||
wacom->transmit_id = 0;
|
||||
wacom->data_pos = 0;
|
||||
wacom->old_tsc = tsc;
|
||||
serial_write_fifo(wacom->serial, fifo8_pop(&wacom->data));
|
||||
if (fifo8_num_used(&wacom->data) == 0) {
|
||||
wacom->old_tsc = tsc;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -360,9 +609,16 @@ wacom_init(const device_t *info)
|
||||
{
|
||||
mouse_wacom_t *dev;
|
||||
|
||||
dev = (mouse_wacom_t *) calloc(1, sizeof(mouse_wacom_t));
|
||||
dev = (mouse_wacom_t *) calloc(1, sizeof(mouse_wacom_t));
|
||||
dev->name = info->name;
|
||||
dev->but = 3;
|
||||
dev->bits = 10;
|
||||
if (info->local == 0) {
|
||||
dev->tablet_type = &sd510_id;
|
||||
} else
|
||||
dev->tablet_type = (wacom_tablet_id*)info->local;
|
||||
|
||||
fifo8_create(&dev->data, 512);
|
||||
|
||||
dev->port = device_get_config_int("port");
|
||||
|
||||
@@ -370,7 +626,11 @@ wacom_init(const device_t *info)
|
||||
timer_add(&dev->report_timer, wacom_report_timer, dev, 0);
|
||||
mouse_set_buttons(dev->but);
|
||||
|
||||
wacom_reset(dev);
|
||||
if (dev->tablet_type->type == WACOM_TYPE_IV) {
|
||||
wacom_reset_artpad(dev);
|
||||
wacom_process_settings_dword(dev, 0xE2018000);
|
||||
}
|
||||
else wacom_reset(dev);
|
||||
|
||||
return dev;
|
||||
}
|
||||
@@ -388,6 +648,8 @@ wacom_close(void *priv)
|
||||
{
|
||||
mouse_wacom_t *dev = (mouse_wacom_t *) priv;
|
||||
|
||||
fifo8_destroy(&dev->data);
|
||||
|
||||
/* Detach serial port from the mouse. */
|
||||
if (dev && dev->serial && dev->serial->sd)
|
||||
memset(dev->serial->sd, 0, sizeof(serial_device_t));
|
||||
@@ -421,7 +683,21 @@ const device_t mouse_wacom_device = {
|
||||
.name = "Wacom SD-510C",
|
||||
.internal_name = "wacom_serial",
|
||||
.flags = DEVICE_COM,
|
||||
.local = MOUSE_TYPE_WACOM,
|
||||
.local = 0,
|
||||
.init = wacom_init,
|
||||
.close = wacom_close,
|
||||
.reset = NULL,
|
||||
{ .poll = wacom_poll },
|
||||
.speed_changed = wacom_speed_changed,
|
||||
.force_redraw = NULL,
|
||||
.config = wacom_config
|
||||
};
|
||||
|
||||
const device_t mouse_wacom_artpad_device = {
|
||||
.name = "Wacom ArtPad",
|
||||
.internal_name = "wacom_serial_artpad",
|
||||
.flags = DEVICE_COM,
|
||||
.local = (uintptr_t)&artpad_id,
|
||||
.init = wacom_init,
|
||||
.close = wacom_close,
|
||||
.reset = NULL,
|
||||
|
||||
@@ -152,7 +152,7 @@ serial_clear_timeout(serial_t *dev)
|
||||
static void
|
||||
serial_receive_timer(void *priv)
|
||||
{
|
||||
serial_t *dev = (serial_t *) priv;
|
||||
serial_t *dev = (serial_t *) priv;
|
||||
|
||||
// serial_log("serial_receive_timer()\n");
|
||||
|
||||
@@ -211,8 +211,7 @@ write_fifo(serial_t *dev, uint8_t dat)
|
||||
{
|
||||
serial_log("write_fifo(%08X, %02X, %i, %i)\n", dev, dat,
|
||||
(dev->type >= SERIAL_16550) && dev->fifo_enabled,
|
||||
((dev->type >= SERIAL_16550) && dev->fifo_enabled) ?
|
||||
(dev->rcvr_fifo_pos % dev->rcvr_fifo_len) : 0);
|
||||
((dev->type >= SERIAL_16550) && dev->fifo_enabled) ? (dev->rcvr_fifo_pos % dev->rcvr_fifo_len) : 0);
|
||||
|
||||
if ((dev->type >= SERIAL_16550) && dev->fifo_enabled) {
|
||||
/* FIFO mode. */
|
||||
@@ -560,7 +559,7 @@ serial_write(uint16_t addr, uint8_t val, void *p)
|
||||
dev->rcvr_fifo_len = 14;
|
||||
break;
|
||||
}
|
||||
dev->out_new = 0xffff;
|
||||
dev->out_new = 0xffff;
|
||||
serial_log("FIFO now %sabled, receive FIFO length = %i\n", dev->fifo_enabled ? "en" : "dis", dev->rcvr_fifo_len);
|
||||
}
|
||||
break;
|
||||
@@ -665,7 +664,7 @@ serial_read(uint16_t addr, void *p)
|
||||
|
||||
if (dev->rcvr_fifo_full || (dev->rcvr_fifo_pos != dev->rcvr_fifo_end)) {
|
||||
/* There is data in the FIFO. */
|
||||
ret = dev->rcvr_fifo[dev->rcvr_fifo_pos];
|
||||
ret = dev->rcvr_fifo[dev->rcvr_fifo_pos];
|
||||
dev->rcvr_fifo_pos = (dev->rcvr_fifo_pos + 1) & 0x0f;
|
||||
|
||||
/* Make sure to clear the FIFO full condition. */
|
||||
@@ -690,7 +689,7 @@ serial_read(uint16_t addr, void *p)
|
||||
} else {
|
||||
/* Non-FIFO mode. */
|
||||
|
||||
ret = (uint8_t) (dev->out_new & 0xffff);
|
||||
ret = (uint8_t) (dev->out_new & 0xffff);
|
||||
dev->out_new = 0xffff;
|
||||
|
||||
/* Always clear Data Ready interrupt. */
|
||||
@@ -857,8 +856,8 @@ serial_reset(void *priv)
|
||||
|
||||
serial_reset_port(dev);
|
||||
|
||||
dev->dlab = 96;
|
||||
dev->fcr = 0x06;
|
||||
dev->dlab = 96;
|
||||
dev->fcr = 0x06;
|
||||
|
||||
serial_transmit_period(dev);
|
||||
serial_update_speed(dev);
|
||||
@@ -889,8 +888,8 @@ serial_init(const device_t *info)
|
||||
serial_setup(dev, COM1_ADDR, COM1_IRQ);
|
||||
|
||||
/* Default to 1200,N,7. */
|
||||
dev->dlab = 96;
|
||||
dev->fcr = 0x06;
|
||||
dev->dlab = 96;
|
||||
dev->fcr = 0x06;
|
||||
if (info->local == SERIAL_8250_PCJR)
|
||||
dev->clock_src = 1789500.0;
|
||||
else
|
||||
|
||||
@@ -88,7 +88,7 @@ discord_update_activity(int paused)
|
||||
*(paren - 1) = '\0';
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#if defined(__GNUC__) && !defined (__clang__)
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
# pragma GCC diagnostic ignored "-Wformat-truncation"
|
||||
#endif
|
||||
if (strlen(vm_name) < 100) {
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
* Copyright 2016-2020 Miran Grca.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
@@ -737,7 +738,7 @@ ide_set_signature(ide_t *ide)
|
||||
ide->secount = ide->sc->phase;
|
||||
ide->cylinder = ide->sc->request_length;
|
||||
} else {
|
||||
ide->secount = 1;
|
||||
ide->secount = 1;
|
||||
// ide->cylinder = ((ide->type == IDE_HDD) ? 0 : 0xFFFF);
|
||||
ide->cylinder = ((ide->type == IDE_HDD) ? 0 : 0x7F7F);
|
||||
if (ide->type == IDE_HDD)
|
||||
@@ -1919,9 +1920,9 @@ ide_readb(uint16_t addr, void *priv)
|
||||
addr &= 0xFFF7;
|
||||
|
||||
if ((ide->type == IDE_NONE) && ((ide_drives[ch ^ 1]->type == IDE_NONE) || !(ch & 1)))
|
||||
absent = 1; /* Absent and is master or both are absent. */
|
||||
absent = 1; /* Absent and is master or both are absent. */
|
||||
else if ((ide->type == IDE_NONE) && (ch & 1))
|
||||
absent = 2; /* Absent and is slave and master is present. */
|
||||
absent = 2; /* Absent and is slave and master is present. */
|
||||
|
||||
switch (addr & 0x7) {
|
||||
case 0x0: /* Data */
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
#include <86box/hdc.h>
|
||||
#include <86box/hdd.h>
|
||||
|
||||
#define HDC_TIME (50 * TIMER_USEC)
|
||||
#define HDC_TIME (50 * TIMER_USEC)
|
||||
|
||||
#define WD_REV_1_BIOS_FILE "roms/hdd/xta/idexywd2.bin"
|
||||
#define WD_REV_2_BIOS_FILE "roms/hdd/xta/infowdbios.rom"
|
||||
@@ -968,7 +968,7 @@ xta_init(const device_t *info)
|
||||
{
|
||||
drive_t *drive;
|
||||
char *bios_rev = NULL;
|
||||
char *fn = NULL;
|
||||
char *fn = NULL;
|
||||
hdc_t *dev;
|
||||
int c, i;
|
||||
int max = XTA_NUM;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -32,7 +33,7 @@
|
||||
#include <86box/random.h>
|
||||
#include <86box/hdd.h>
|
||||
#include "minivhd/minivhd.h"
|
||||
#include "minivhd/minivhd_internal.h"
|
||||
#include "minivhd/internal.h"
|
||||
|
||||
#define HDD_IMAGE_RAW 0
|
||||
#define HDD_IMAGE_HDI 1
|
||||
|
||||
@@ -13,6 +13,5 @@
|
||||
# Copyright 2020,2021 David Hrdlička.
|
||||
#
|
||||
|
||||
add_library(minivhd STATIC cwalk.c libxml2_encoding.c minivhd_convert.c
|
||||
minivhd_create.c minivhd_io.c minivhd_manage.c minivhd_struct_rw.c
|
||||
minivhd_util.c)
|
||||
add_library(minivhd STATIC cwalk.c xml2_encoding.c convert.c
|
||||
create.c minivhd_io.c manage.c struct_rw.c minivhd_util.c)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Credits
|
||||
MiniVHD Copyright (c) 2019 Sherman Perry
|
||||
MiniVHD Copyright 2019-2021 Sherman Perry.
|
||||
|
||||
MiniVHD was made possible with the help of the following projects
|
||||
MiniVHD was made possible with the help of the following projects:
|
||||
|
||||
### libxml2
|
||||
**Project Home:** http://www.xmlsoft.org/
|
||||
@@ -10,3 +10,8 @@ MiniVHD was made possible with the help of the following projects
|
||||
### cwalk
|
||||
**Project Home:** https://likle.github.io/cwalk/
|
||||
**Licence:** MIT (https://github.com/likle/cwalk/blob/master/LICENSE.md)
|
||||
|
||||
### VARCem
|
||||
The MiniVHD was rewritten into a standalone library (both shared as well
|
||||
as static) by Fred N. van Kempen for use with the VARCem PC Systems
|
||||
emulator - see https://www.varcem.com/ for more info.
|
||||
|
||||
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
SOFTWARE.
|
||||
@@ -1,28 +1,66 @@
|
||||
/*
|
||||
* MiniVHD Minimalist VHD implementation in C.
|
||||
*
|
||||
* This file is part of the MiniVHD Project.
|
||||
*
|
||||
* Version: @(#)convert.c 1.0.2 2021/04/16
|
||||
*
|
||||
* Authors: Sherman Perry, <shermperry@gmail.com>
|
||||
* Fred N. van Kempen, <waltje@varcem.com>
|
||||
*
|
||||
* Copyright 2019-2021 Sherman Perry.
|
||||
* Copyright 2021 Fred N. van Kempen.
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documenta-
|
||||
* tion files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall
|
||||
* be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF O R IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "minivhd_create.h"
|
||||
#include "minivhd_internal.h"
|
||||
#include "minivhd_util.h"
|
||||
#include <time.h>
|
||||
#include "minivhd.h"
|
||||
#include "internal.h"
|
||||
|
||||
static FILE* mvhd_open_existing_raw_img(const char* utf8_raw_path, MVHDGeom* geom, int* err);
|
||||
|
||||
static FILE* mvhd_open_existing_raw_img(const char* utf8_raw_path, MVHDGeom* geom, int* err) {
|
||||
static FILE*
|
||||
open_existing_raw_img(const char* utf8_raw_path, MVHDGeom* geom, int* err)
|
||||
{
|
||||
if (geom == NULL) {
|
||||
*err = MVHD_ERR_INVALID_GEOM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FILE *raw_img = mvhd_fopen(utf8_raw_path, "rb", err);
|
||||
if (raw_img == NULL) {
|
||||
*err = MVHD_ERR_FILE;
|
||||
return NULL;
|
||||
}
|
||||
if (geom == NULL) {
|
||||
*err = MVHD_ERR_INVALID_GEOM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mvhd_fseeko64(raw_img, 0, SEEK_END);
|
||||
uint64_t size_bytes = (uint64_t)mvhd_ftello64(raw_img);
|
||||
MVHDGeom new_geom = mvhd_calculate_geometry(size_bytes);
|
||||
@@ -34,37 +72,52 @@ static FILE* mvhd_open_existing_raw_img(const char* utf8_raw_path, MVHDGeom* geo
|
||||
geom->heads = new_geom.heads;
|
||||
geom->spt = new_geom.spt;
|
||||
mvhd_fseeko64(raw_img, 0, SEEK_SET);
|
||||
|
||||
return raw_img;
|
||||
}
|
||||
|
||||
MVHDMeta* mvhd_convert_to_vhd_fixed(const char* utf8_raw_path, const char* utf8_vhd_path, int* err) {
|
||||
|
||||
MVHDAPI MVHDMeta*
|
||||
mvhd_convert_to_vhd_fixed(const char* utf8_raw_path, const char* utf8_vhd_path, int* err)
|
||||
{
|
||||
MVHDGeom geom;
|
||||
FILE *raw_img = mvhd_open_existing_raw_img(utf8_raw_path, &geom, err);
|
||||
|
||||
FILE *raw_img = open_existing_raw_img(utf8_raw_path, &geom, err);
|
||||
if (raw_img == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint64_t size_in_bytes = mvhd_calc_size_bytes(&geom);
|
||||
MVHDMeta *vhdm = mvhd_create_fixed_raw(utf8_vhd_path, raw_img, size_in_bytes, &geom, err, NULL);
|
||||
if (vhdm == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return vhdm;
|
||||
}
|
||||
MVHDMeta* mvhd_convert_to_vhd_sparse(const char* utf8_raw_path, const char* utf8_vhd_path, int* err) {
|
||||
|
||||
|
||||
MVHDAPI MVHDMeta*
|
||||
mvhd_convert_to_vhd_sparse(const char* utf8_raw_path, const char* utf8_vhd_path, int* err)
|
||||
{
|
||||
MVHDGeom geom;
|
||||
MVHDMeta *vhdm = NULL;
|
||||
FILE *raw_img = mvhd_open_existing_raw_img(utf8_raw_path, &geom, err);
|
||||
|
||||
FILE *raw_img = open_existing_raw_img(utf8_raw_path, &geom, err);
|
||||
if (raw_img == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vhdm = mvhd_create_sparse(utf8_vhd_path, geom, err);
|
||||
if (vhdm == NULL) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
uint8_t buff[4096] = {0}; // 8 sectors
|
||||
uint8_t empty_buff[4096] = {0};
|
||||
int total_sectors = mvhd_calc_size_sectors(&geom);
|
||||
int copy_sect = 0;
|
||||
|
||||
for (int i = 0; i < total_sectors; i += 8) {
|
||||
copy_sect = 8;
|
||||
if ((i + 8) >= total_sectors) {
|
||||
@@ -72,6 +125,7 @@ MVHDMeta* mvhd_convert_to_vhd_sparse(const char* utf8_raw_path, const char* utf8
|
||||
memset(buff, 0, sizeof buff);
|
||||
}
|
||||
(void) !fread(buff, MVHD_SECTOR_SIZE, copy_sect, raw_img);
|
||||
|
||||
/* Only write data if there's data to write, to take advantage of the sparse VHD format */
|
||||
if (memcmp(buff, empty_buff, sizeof buff) != 0) {
|
||||
mvhd_write_sectors(vhdm, i, copy_sect, buff);
|
||||
@@ -79,18 +133,25 @@ MVHDMeta* mvhd_convert_to_vhd_sparse(const char* utf8_raw_path, const char* utf8
|
||||
}
|
||||
end:
|
||||
fclose(raw_img);
|
||||
|
||||
return vhdm;
|
||||
}
|
||||
FILE* mvhd_convert_to_raw(const char* utf8_vhd_path, const char* utf8_raw_path, int *err) {
|
||||
|
||||
|
||||
MVHDAPI FILE*
|
||||
mvhd_convert_to_raw(const char* utf8_vhd_path, const char* utf8_raw_path, int *err)
|
||||
{
|
||||
FILE *raw_img = mvhd_fopen(utf8_raw_path, "wb", err);
|
||||
if (raw_img == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MVHDMeta *vhdm = mvhd_open(utf8_vhd_path, true, err);
|
||||
if (vhdm == NULL) {
|
||||
fclose(raw_img);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t buff[4096] = {0}; // 8 sectors
|
||||
int total_sectors = mvhd_calc_size_sectors((MVHDGeom*)&vhdm->footer.geom);
|
||||
int copy_sect = 0;
|
||||
@@ -104,5 +165,6 @@ FILE* mvhd_convert_to_raw(const char* utf8_vhd_path, const char* utf8_raw_path,
|
||||
}
|
||||
mvhd_close(vhdm);
|
||||
mvhd_fseeko64(raw_img, 0, SEEK_SET);
|
||||
|
||||
return raw_img;
|
||||
}
|
||||
@@ -1,30 +1,60 @@
|
||||
/*
|
||||
* MiniVHD Minimalist VHD implementation in C.
|
||||
*
|
||||
* This file is part of the MiniVHD Project.
|
||||
*
|
||||
* Version: @(#)create.c 1.0.3 2021/04/16
|
||||
*
|
||||
* Authors: Sherman Perry, <shermperry@gmail.com>
|
||||
* Fred N. van Kempen, <waltje@varcem.com>
|
||||
*
|
||||
* Copyright 2019-2021 Sherman Perry.
|
||||
* Copyright 2021 Fred N. van Kempen.
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documenta-
|
||||
* tion files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall
|
||||
* be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF O R IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "cwalk.h"
|
||||
#include "libxml2_encoding.h"
|
||||
#include "minivhd_internal.h"
|
||||
#include "minivhd_util.h"
|
||||
#include "minivhd_struct_rw.h"
|
||||
#include "minivhd_io.h"
|
||||
#include "minivhd_create.h"
|
||||
#include <time.h>
|
||||
#include "minivhd.h"
|
||||
#include "internal.h"
|
||||
#include "cwalk.h"
|
||||
#include "xml2_encoding.h"
|
||||
|
||||
|
||||
static const char MVHD_CONECTIX_COOKIE[] = "conectix";
|
||||
static const char MVHD_CREATOR[] = "mVHD";
|
||||
static const char MVHD_CREATOR_HOST_OS[] = "Wi2k";
|
||||
static const char MVHD_CXSPARSE_COOKIE[] = "cxsparse";
|
||||
|
||||
static void mvhd_gen_footer(MVHDFooter* footer, uint64_t size_in_bytes, MVHDGeom* geom, MVHDType type, uint64_t sparse_header_off);
|
||||
static void mvhd_gen_sparse_header(MVHDSparseHeader* header, uint32_t num_blks, uint64_t bat_offset, uint32_t block_size_in_sectors);
|
||||
static int mvhd_gen_par_loc(MVHDSparseHeader* header,
|
||||
const char* child_path,
|
||||
const char* par_path,
|
||||
uint64_t start_offset,
|
||||
mvhd_utf16* w2ku_path_buff,
|
||||
mvhd_utf16* w2ru_path_buff,
|
||||
MVHDError* err);
|
||||
static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, uint64_t size_in_bytes, MVHDGeom* geom, uint32_t block_size_in_sectors, int* err);
|
||||
|
||||
/**
|
||||
* \brief Populate a VHD footer
|
||||
@@ -35,24 +65,29 @@ static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path,
|
||||
* \param [in] type of HVD that is being created
|
||||
* \param [in] sparse_header_off, an absolute file offset to the sparse header. Not used for fixed VHD images
|
||||
*/
|
||||
static void mvhd_gen_footer(MVHDFooter* footer, uint64_t size_in_bytes, MVHDGeom* geom, MVHDType type, uint64_t sparse_header_off) {
|
||||
memcpy(footer->cookie, "conectix", sizeof footer->cookie);
|
||||
static void
|
||||
gen_footer(MVHDFooter* footer, uint64_t size_in_bytes, MVHDGeom* geom, MVHDType type, uint64_t sparse_header_off)
|
||||
{
|
||||
memcpy(footer->cookie, MVHD_CONECTIX_COOKIE, sizeof footer->cookie);
|
||||
footer->features = 0x00000002;
|
||||
footer->fi_fmt_vers = 0x00010000;
|
||||
footer->data_offset = (type == MVHD_TYPE_DIFF || type == MVHD_TYPE_DYNAMIC) ? sparse_header_off : 0xffffffffffffffff;
|
||||
footer->timestamp = vhd_calc_timestamp();
|
||||
memcpy(footer->cr_app, "mvhd", sizeof footer->cr_app);
|
||||
memcpy(footer->cr_app, MVHD_CREATOR, sizeof footer->cr_app);
|
||||
footer->cr_vers = 0x000e0000;
|
||||
memcpy(footer->cr_host_os, "Wi2k", sizeof footer->cr_host_os);
|
||||
memcpy(footer->cr_host_os, MVHD_CREATOR_HOST_OS, sizeof footer->cr_host_os);
|
||||
footer->orig_sz = footer->curr_sz = size_in_bytes;
|
||||
footer->geom.cyl = geom->cyl;
|
||||
footer->geom.heads = geom->heads;
|
||||
footer->geom.spt = geom->spt;
|
||||
footer->disk_type = type;
|
||||
|
||||
mvhd_generate_uuid(footer->uuid);
|
||||
|
||||
footer->checksum = mvhd_gen_footer_checksum(footer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Populate a VHD sparse header
|
||||
*
|
||||
@@ -61,8 +96,10 @@ static void mvhd_gen_footer(MVHDFooter* footer, uint64_t size_in_bytes, MVHDGeom
|
||||
* \param [in] bat_offset is the absolute file offset for start of the Block Allocation Table
|
||||
* \param [in] block_size_in_sectors is the block size in sectors.
|
||||
*/
|
||||
static void mvhd_gen_sparse_header(MVHDSparseHeader* header, uint32_t num_blks, uint64_t bat_offset, uint32_t block_size_in_sectors) {
|
||||
memcpy(header->cookie, "cxsparse", sizeof header->cookie);
|
||||
static void
|
||||
gen_sparse_header(MVHDSparseHeader* header, uint32_t num_blks, uint64_t bat_offset, uint32_t block_size_in_sectors)
|
||||
{
|
||||
memcpy(header->cookie, MVHD_CXSPARSE_COOKIE, sizeof header->cookie);
|
||||
header->data_offset = 0xffffffffffffffff;
|
||||
header->bat_offset = bat_offset;
|
||||
header->head_vers = 0x00010000;
|
||||
@@ -71,6 +108,7 @@ static void mvhd_gen_sparse_header(MVHDSparseHeader* header, uint32_t num_blks,
|
||||
header->checksum = mvhd_gen_sparse_checksum(header);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Generate parent locators for differencing VHD images
|
||||
*
|
||||
@@ -85,13 +123,12 @@ static void mvhd_gen_sparse_header(MVHDSparseHeader* header, uint32_t num_blks,
|
||||
* \retval 0 if success
|
||||
* \retval < 0 if an error occurrs. Check value of *err for actual error
|
||||
*/
|
||||
static int mvhd_gen_par_loc(MVHDSparseHeader* header,
|
||||
const char* child_path,
|
||||
const char* par_path,
|
||||
uint64_t start_offset,
|
||||
mvhd_utf16* w2ku_path_buff,
|
||||
mvhd_utf16* w2ru_path_buff,
|
||||
MVHDError* err) {
|
||||
static int
|
||||
gen_par_loc(MVHDSparseHeader* header, const char* child_path,
|
||||
const char* par_path, uint64_t start_offset,
|
||||
mvhd_utf16* w2ku_path_buff, mvhd_utf16* w2ru_path_buff,
|
||||
MVHDError* err)
|
||||
{
|
||||
/* Get our paths to store in the differencing VHD. We want both the absolute path to the parent,
|
||||
as well as the relative path from the child VHD */
|
||||
int rv = 0;
|
||||
@@ -100,6 +137,7 @@ static int mvhd_gen_par_loc(MVHDSparseHeader* header,
|
||||
char rel_path[MVHD_MAX_PATH_BYTES] = {0};
|
||||
char child_dir[MVHD_MAX_PATH_BYTES] = {0};
|
||||
size_t child_dir_len;
|
||||
|
||||
if (strlen(child_path) < sizeof child_dir) {
|
||||
strcpy(child_dir, child_path);
|
||||
} else {
|
||||
@@ -107,6 +145,7 @@ static int mvhd_gen_par_loc(MVHDSparseHeader* header,
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
cwk_path_get_basename(par_path, (const char**)&par_filename, &par_fn_len);
|
||||
cwk_path_get_dirname(child_dir, &child_dir_len);
|
||||
child_dir[child_dir_len] = '\0';
|
||||
@@ -116,6 +155,7 @@ static int mvhd_gen_par_loc(MVHDSparseHeader* header,
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* We have our paths, now store the parent filename directly in the sparse header. */
|
||||
int outlen = sizeof header->par_utf16_name;
|
||||
int utf_ret;
|
||||
@@ -144,6 +184,7 @@ static int mvhd_gen_par_loc(MVHDSparseHeader* header,
|
||||
goto end;
|
||||
}
|
||||
int w2ru_len = utf_ret;
|
||||
|
||||
/**
|
||||
* Finally populate the parent locaters in the sparse header.
|
||||
* This is the information needed to find the paths saved elsewhere
|
||||
@@ -169,11 +210,16 @@ end:
|
||||
return rv;
|
||||
}
|
||||
|
||||
MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* err, mvhd_progress_callback progress_callback) {
|
||||
|
||||
MVHDAPI MVHDMeta*
|
||||
mvhd_create_fixed(const char* path, MVHDGeom geom, int* err, mvhd_progress_callback progress_callback)
|
||||
{
|
||||
uint64_t size_in_bytes = mvhd_calc_size_bytes(&geom);
|
||||
|
||||
return mvhd_create_fixed_raw(path, NULL, size_in_bytes, &geom, err, progress_callback);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief internal function that implements public mvhd_create_fixed() functionality
|
||||
*
|
||||
@@ -182,27 +228,35 @@ MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* err, mvhd_prog
|
||||
*
|
||||
* \param [in] raw_image file handle to a raw disk image to populate VHD
|
||||
*/
|
||||
MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, uint64_t size_in_bytes, MVHDGeom* geom, int* err, mvhd_progress_callback progress_callback) {
|
||||
MVHDMeta*
|
||||
mvhd_create_fixed_raw(const char* path, FILE* raw_img, uint64_t size_in_bytes, MVHDGeom* geom, int* err, mvhd_progress_callback progress_callback)
|
||||
{
|
||||
uint8_t img_data[MVHD_SECTOR_SIZE] = {0};
|
||||
uint8_t footer_buff[MVHD_FOOTER_SIZE] = {0};
|
||||
|
||||
if (geom == NULL || (geom->cyl == 0 || geom->heads == 0 || geom->spt == 0)) {
|
||||
*err = MVHD_ERR_INVALID_GEOM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MVHDMeta* vhdm = calloc(1, sizeof *vhdm);
|
||||
if (vhdm == NULL) {
|
||||
*err = MVHD_ERR_MEM;
|
||||
goto end;
|
||||
}
|
||||
if (geom == NULL || (geom->cyl == 0 || geom->heads == 0 || geom->spt == 0)) {
|
||||
*err = MVHD_ERR_INVALID_GEOM;
|
||||
goto cleanup_vhdm;
|
||||
}
|
||||
|
||||
FILE* f = mvhd_fopen(path, "wb+", err);
|
||||
if (f == NULL) {
|
||||
goto cleanup_vhdm;
|
||||
}
|
||||
mvhd_fseeko64(f, 0, SEEK_SET);
|
||||
|
||||
uint32_t size_sectors = (uint32_t)(size_in_bytes / MVHD_SECTOR_SIZE);
|
||||
uint32_t s;
|
||||
|
||||
if (progress_callback)
|
||||
progress_callback(0, size_sectors);
|
||||
|
||||
if (raw_img != NULL) {
|
||||
mvhd_fseeko64(raw_img, 0, SEEK_END);
|
||||
uint64_t raw_size = (uint64_t)mvhd_ftello64(raw_img);
|
||||
@@ -211,7 +265,7 @@ MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, uint64_t size_i
|
||||
*err = MVHD_ERR_CONV_SIZE;
|
||||
goto cleanup_vhdm;
|
||||
}
|
||||
mvhd_gen_footer(&vhdm->footer, raw_size, geom, MVHD_TYPE_FIXED, 0);
|
||||
gen_footer(&vhdm->footer, raw_size, geom, MVHD_TYPE_FIXED, 0);
|
||||
mvhd_fseeko64(raw_img, 0, SEEK_SET);
|
||||
for (s = 0; s < size_sectors; s++) {
|
||||
(void) !fread(img_data, sizeof img_data, 1, raw_img);
|
||||
@@ -220,7 +274,7 @@ MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, uint64_t size_i
|
||||
progress_callback(s + 1, size_sectors);
|
||||
}
|
||||
} else {
|
||||
mvhd_gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_FIXED, 0);
|
||||
gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_FIXED, 0);
|
||||
for (s = 0; s < size_sectors; s++) {
|
||||
fwrite(img_data, sizeof img_data, 1, f);
|
||||
if (progress_callback)
|
||||
@@ -238,10 +292,12 @@ MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, uint64_t size_i
|
||||
cleanup_vhdm:
|
||||
free(vhdm);
|
||||
vhdm = NULL;
|
||||
|
||||
end:
|
||||
return vhdm;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Create sparse or differencing VHD image.
|
||||
*
|
||||
@@ -254,7 +310,9 @@ end:
|
||||
*
|
||||
* \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct
|
||||
*/
|
||||
static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, uint64_t size_in_bytes, MVHDGeom* geom, uint32_t block_size_in_sectors, int* err) {
|
||||
static MVHDMeta*
|
||||
create_sparse_diff(const char* path, const char* par_path, uint64_t size_in_bytes, MVHDGeom* geom, uint32_t block_size_in_sectors, int* err)
|
||||
{
|
||||
uint8_t footer_buff[MVHD_FOOTER_SIZE] = {0};
|
||||
uint8_t sparse_buff[MVHD_SPARSE_SIZE] = {0};
|
||||
uint8_t bat_sect[MVHD_SECTOR_SIZE];
|
||||
@@ -265,6 +323,7 @@ static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path,
|
||||
mvhd_utf16* w2ku_path_buff = NULL;
|
||||
mvhd_utf16* w2ru_path_buff = NULL;
|
||||
uint32_t par_mod_timestamp = 0;
|
||||
|
||||
if (par_path != NULL) {
|
||||
par_mod_timestamp = mvhd_file_mod_timestamp(par_path, err);
|
||||
if (*err != 0) {
|
||||
@@ -275,6 +334,7 @@ static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path,
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
vhdm = calloc(1, sizeof *vhdm);
|
||||
if (vhdm == NULL) {
|
||||
*err = MVHD_ERR_MEM;
|
||||
@@ -297,15 +357,18 @@ static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path,
|
||||
goto cleanup_vhdm;
|
||||
}
|
||||
mvhd_fseeko64(f, 0, SEEK_SET);
|
||||
|
||||
/* Note, the sparse header follows the footer copy at the beginning of the file */
|
||||
if (par_path == NULL) {
|
||||
mvhd_gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_DYNAMIC, MVHD_FOOTER_SIZE);
|
||||
gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_DYNAMIC, MVHD_FOOTER_SIZE);
|
||||
} else {
|
||||
mvhd_gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_DIFF, MVHD_FOOTER_SIZE);
|
||||
gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_DIFF, MVHD_FOOTER_SIZE);
|
||||
}
|
||||
mvhd_footer_to_buffer(&vhdm->footer, footer_buff);
|
||||
|
||||
/* As mentioned, start with a copy of the footer */
|
||||
fwrite(footer_buff, sizeof footer_buff, 1, f);
|
||||
|
||||
/**
|
||||
* Calculate the number of (2MB or 512KB) data blocks required to store the entire
|
||||
* contents of the disk image, followed by the number of sectors the
|
||||
@@ -347,43 +410,51 @@ static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path,
|
||||
}
|
||||
memcpy(vhdm->sparse.par_uuid, par_vhdm->footer.uuid, sizeof vhdm->sparse.par_uuid);
|
||||
par_loc_offset = bat_offset + ((uint64_t)num_bat_sect * MVHD_SECTOR_SIZE) + (5 * MVHD_SECTOR_SIZE);
|
||||
if (mvhd_gen_par_loc(&vhdm->sparse, path, par_path, par_loc_offset, w2ku_path_buff, w2ru_path_buff, (MVHDError*)err) < 0) {
|
||||
if (gen_par_loc(&vhdm->sparse, path, par_path, par_loc_offset, w2ku_path_buff, w2ru_path_buff, (MVHDError*)err) < 0) {
|
||||
goto cleanup_vhdm;
|
||||
}
|
||||
vhdm->sparse.par_timestamp = par_mod_timestamp;
|
||||
}
|
||||
mvhd_gen_sparse_header(&vhdm->sparse, num_blks, bat_offset, block_size_in_sectors);
|
||||
gen_sparse_header(&vhdm->sparse, num_blks, bat_offset, block_size_in_sectors);
|
||||
mvhd_header_to_buffer(&vhdm->sparse, sparse_buff);
|
||||
fwrite(sparse_buff, sizeof sparse_buff, 1, f);
|
||||
|
||||
/* The BAT sectors need to be filled with 0xffffffff */
|
||||
for (uint32_t i = 0; i < num_bat_sect; i++) {
|
||||
for (uint32_t k = 0; k < num_bat_sect; k++) {
|
||||
fwrite(bat_sect, sizeof bat_sect, 1, f);
|
||||
}
|
||||
mvhd_write_empty_sectors(f, 5);
|
||||
|
||||
/**
|
||||
* If creating a differencing VHD, the paths to the parent image need to be written
|
||||
* tp the file. Both absolute and relative paths are written
|
||||
* */
|
||||
if (par_vhdm != NULL) {
|
||||
uint64_t curr_pos = (uint64_t)mvhd_ftello64(f);
|
||||
|
||||
/* Double check my sums... */
|
||||
assert(curr_pos == par_loc_offset);
|
||||
|
||||
/* Fill the space required for location data with zero */
|
||||
uint8_t empty_sect[MVHD_SECTOR_SIZE] = {0};
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (uint32_t j = 0; j < (vhdm->sparse.par_loc_entry[i].plat_data_space / MVHD_SECTOR_SIZE); j++) {
|
||||
fwrite(empty_sect, sizeof empty_sect, 1, f);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now write the location entries */
|
||||
mvhd_fseeko64(f, vhdm->sparse.par_loc_entry[0].plat_data_offset, SEEK_SET);
|
||||
fwrite(w2ku_path_buff, vhdm->sparse.par_loc_entry[0].plat_data_len, 1, f);
|
||||
mvhd_fseeko64(f, vhdm->sparse.par_loc_entry[1].plat_data_offset, SEEK_SET);
|
||||
fwrite(w2ru_path_buff, vhdm->sparse.par_loc_entry[1].plat_data_len, 1, f);
|
||||
|
||||
/* and reset the file position to continue */
|
||||
mvhd_fseeko64(f, vhdm->sparse.par_loc_entry[1].plat_data_offset + vhdm->sparse.par_loc_entry[1].plat_data_space, SEEK_SET);
|
||||
mvhd_write_empty_sectors(f, 5);
|
||||
}
|
||||
|
||||
/* And finish with the footer */
|
||||
fwrite(footer_buff, sizeof footer_buff, 1, f);
|
||||
fclose(f);
|
||||
@@ -395,91 +466,112 @@ static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path,
|
||||
cleanup_vhdm:
|
||||
free(vhdm);
|
||||
vhdm = NULL;
|
||||
|
||||
cleanup_par_vhdm:
|
||||
if (par_vhdm != NULL) {
|
||||
mvhd_close(par_vhdm);
|
||||
}
|
||||
|
||||
end:
|
||||
free(w2ku_path_buff);
|
||||
free(w2ru_path_buff);
|
||||
|
||||
return vhdm;
|
||||
}
|
||||
|
||||
MVHDMeta* mvhd_create_sparse(const char* path, MVHDGeom geom, int* err) {
|
||||
|
||||
MVHDAPI MVHDMeta*
|
||||
mvhd_create_sparse(const char* path, MVHDGeom geom, int* err)
|
||||
{
|
||||
uint64_t size_in_bytes = mvhd_calc_size_bytes(&geom);
|
||||
return mvhd_create_sparse_diff(path, NULL, size_in_bytes, &geom, MVHD_BLOCK_LARGE, err);
|
||||
|
||||
return create_sparse_diff(path, NULL, size_in_bytes, &geom, MVHD_BLOCK_LARGE, err);
|
||||
}
|
||||
|
||||
MVHDMeta* mvhd_create_diff(const char* path, const char* par_path, int* err) {
|
||||
return mvhd_create_sparse_diff(path, par_path, 0, NULL, MVHD_BLOCK_LARGE, err);
|
||||
|
||||
MVHDAPI MVHDMeta*
|
||||
mvhd_create_diff(const char* path, const char* par_path, int* err)
|
||||
{
|
||||
return create_sparse_diff(path, par_path, 0, NULL, MVHD_BLOCK_LARGE, err);
|
||||
}
|
||||
|
||||
MVHDMeta* mvhd_create_ex(MVHDCreationOptions options, int* err) {
|
||||
|
||||
MVHDAPI MVHDMeta*
|
||||
mvhd_create_ex(MVHDCreationOptions options, int* err)
|
||||
{
|
||||
uint32_t geom_sector_size;
|
||||
switch (options.type)
|
||||
{
|
||||
case MVHD_TYPE_FIXED:
|
||||
case MVHD_TYPE_DYNAMIC:
|
||||
geom_sector_size = mvhd_calc_size_sectors(&(options.geometry));
|
||||
if ((options.size_in_bytes > 0 && (options.size_in_bytes % MVHD_SECTOR_SIZE) > 0)
|
||||
|| (options.size_in_bytes > MVHD_MAX_SIZE_IN_BYTES)
|
||||
|| (options.size_in_bytes == 0 && geom_sector_size == 0))
|
||||
{
|
||||
*err = MVHD_ERR_INVALID_SIZE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (options.size_in_bytes > 0 && ((uint64_t)geom_sector_size * MVHD_SECTOR_SIZE) > options.size_in_bytes)
|
||||
{
|
||||
*err = MVHD_ERR_INVALID_GEOM;
|
||||
return NULL;
|
||||
}
|
||||
switch (options.type) {
|
||||
case MVHD_TYPE_FIXED:
|
||||
case MVHD_TYPE_DYNAMIC:
|
||||
geom_sector_size = mvhd_calc_size_sectors(&(options.geometry));
|
||||
if ((options.size_in_bytes > 0 && (options.size_in_bytes % MVHD_SECTOR_SIZE) > 0)
|
||||
|| (options.size_in_bytes > MVHD_MAX_SIZE_IN_BYTES)
|
||||
|| (options.size_in_bytes == 0 && geom_sector_size == 0)) {
|
||||
*err = MVHD_ERR_INVALID_SIZE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (options.size_in_bytes == 0)
|
||||
options.size_in_bytes = (uint64_t)geom_sector_size * MVHD_SECTOR_SIZE;
|
||||
if (options.size_in_bytes > 0 && ((uint64_t)geom_sector_size * MVHD_SECTOR_SIZE) > options.size_in_bytes) {
|
||||
*err = MVHD_ERR_INVALID_GEOM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (geom_sector_size == 0)
|
||||
options.geometry = mvhd_calculate_geometry(options.size_in_bytes);
|
||||
break;
|
||||
case MVHD_TYPE_DIFF:
|
||||
if (options.parent_path == NULL)
|
||||
{
|
||||
*err = MVHD_ERR_FILE;
|
||||
if (options.size_in_bytes == 0)
|
||||
options.size_in_bytes = (uint64_t)geom_sector_size * MVHD_SECTOR_SIZE;
|
||||
|
||||
if (geom_sector_size == 0)
|
||||
options.geometry = mvhd_calculate_geometry(options.size_in_bytes);
|
||||
break;
|
||||
|
||||
case MVHD_TYPE_DIFF:
|
||||
if (options.parent_path == NULL) {
|
||||
*err = MVHD_ERR_FILE;
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
*err = MVHD_ERR_TYPE;
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*err = MVHD_ERR_TYPE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (options.path == NULL)
|
||||
{
|
||||
if (options.path == NULL) {
|
||||
*err = MVHD_ERR_FILE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (options.type != MVHD_TYPE_FIXED)
|
||||
{
|
||||
if (options.type != MVHD_TYPE_FIXED) {
|
||||
if (options.block_size_in_sectors == MVHD_BLOCK_DEFAULT)
|
||||
options.block_size_in_sectors = MVHD_BLOCK_LARGE;
|
||||
|
||||
if (options.block_size_in_sectors != MVHD_BLOCK_LARGE && options.block_size_in_sectors != MVHD_BLOCK_SMALL)
|
||||
{
|
||||
if (options.block_size_in_sectors != MVHD_BLOCK_LARGE && options.block_size_in_sectors != MVHD_BLOCK_SMALL) {
|
||||
*err = MVHD_ERR_INVALID_BLOCK_SIZE;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
switch (options.type)
|
||||
{
|
||||
case MVHD_TYPE_FIXED:
|
||||
return mvhd_create_fixed_raw(options.path, NULL, options.size_in_bytes, &(options.geometry), err, options.progress_callback);
|
||||
case MVHD_TYPE_DYNAMIC:
|
||||
return mvhd_create_sparse_diff(options.path, NULL, options.size_in_bytes, &(options.geometry), options.block_size_in_sectors, err);
|
||||
case MVHD_TYPE_DIFF:
|
||||
return mvhd_create_sparse_diff(options.path, options.parent_path, 0, NULL, options.block_size_in_sectors, err);
|
||||
switch (options.type) {
|
||||
case MVHD_TYPE_FIXED:
|
||||
return mvhd_create_fixed_raw(options.path, NULL, options.size_in_bytes, &(options.geometry), err, options.progress_callback);
|
||||
|
||||
case MVHD_TYPE_DYNAMIC:
|
||||
return create_sparse_diff(options.path, NULL, options.size_in_bytes, &(options.geometry), options.block_size_in_sectors, err);
|
||||
|
||||
case MVHD_TYPE_DIFF:
|
||||
return create_sparse_diff(options.path, options.parent_path, 0, NULL, options.block_size_in_sectors, err);
|
||||
}
|
||||
|
||||
return NULL; /* Make the compiler happy */
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
mvhd_is_conectix_str(const void* buffer)
|
||||
{
|
||||
if (strncmp(buffer, MVHD_CONECTIX_COOKIE, strlen(MVHD_CONECTIX_COOKIE)) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1,12 +1,49 @@
|
||||
/*
|
||||
* libCWALK Path library for C/C++
|
||||
*
|
||||
* Version: @(#)cwalk.c 1.0.2 2021/03/16
|
||||
*
|
||||
* Authors: Sherman Perry, <shermperry@gmail.com>
|
||||
* Leonard Iklé, <https://github.com/likle>
|
||||
*
|
||||
* Copyright 2019-2021 Sherman Perry.
|
||||
* Copyright 2020 Leonard Iklé.
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documenta-
|
||||
* tion files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall
|
||||
* be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF O R IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "cwalk.h"
|
||||
|
||||
|
||||
/**
|
||||
* We try to default to a different path style depending on the operating
|
||||
* system. So this should detect whether we should use windows or unix paths.
|
||||
|
||||
@@ -1,10 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* libCWALK path library for C/C++
|
||||
*
|
||||
* Version: @(#)cwalk.h 1.0.3 2021/03/22
|
||||
*
|
||||
* Authors: Sherman Perry, <shermperry@gmail.com>
|
||||
* Leonard Iklé, <https://github.com/likle>
|
||||
*
|
||||
* Copyright 2019-2021 Sherman Perry.
|
||||
* Copyright 2020 Leonard Iklé.
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documenta-
|
||||
* tion files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall
|
||||
* be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF O R IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef CWK_LIBRARY_H
|
||||
#define CWK_LIBRARY_H
|
||||
# define CWK_LIBRARY_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* A segment represents a single component of a path. For instance, on linux a
|
||||
@@ -45,6 +75,11 @@ enum cwk_path_style
|
||||
CWK_STYLE_UNIX
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Generates an absolute path based on a base.
|
||||
*
|
||||
@@ -454,4 +489,9 @@ void cwk_path_set_style(enum cwk_path_style style);
|
||||
*/
|
||||
enum cwk_path_style cwk_path_get_style(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*CWK_LIBRARY_H*/
|
||||
|
||||
429
src/disk/minivhd/internal.h
Normal file
429
src/disk/minivhd/internal.h
Normal file
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
* MiniVHD Minimalist VHD implementation in C.
|
||||
*
|
||||
* This file is part of the MiniVHD Project.
|
||||
*
|
||||
* Internal definitions.
|
||||
*
|
||||
* Version: @(#)internal.h 1.0.1 2021/03/15
|
||||
*
|
||||
* Author: Sherman Perry, <shermperry@gmail.com>
|
||||
*
|
||||
* Copyright 2019-2021 Sherman Perry.
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documenta-
|
||||
* tion files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall
|
||||
* be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF O R IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MINIVHD_INTERNAL_H
|
||||
# define MINIVHD_INTERNAL_H
|
||||
|
||||
|
||||
#define MVHD_FOOTER_SIZE 512
|
||||
#define MVHD_SPARSE_SIZE 1024
|
||||
|
||||
#define MVHD_SECTOR_SIZE 512
|
||||
#define MVHD_BAT_ENT_PER_SECT 128
|
||||
|
||||
#define MVHD_MAX_SIZE_IN_BYTES 0x1fe00000000
|
||||
|
||||
#define MVHD_SPARSE_BLK 0xffffffff
|
||||
|
||||
/* For simplicity, we don't handle paths longer than this
|
||||
* Note, this is the max path in characters, as that is what
|
||||
* Windows uses
|
||||
*/
|
||||
#define MVHD_MAX_PATH_CHARS 260
|
||||
#define MVHD_MAX_PATH_BYTES 1040
|
||||
|
||||
#define MVHD_DIF_LOC_W2RU 0x57327275
|
||||
#define MVHD_DIF_LOC_W2KU 0x57326B75
|
||||
|
||||
#define MVHD_START_TS 946684800
|
||||
|
||||
|
||||
typedef struct MVHDSectorBitmap {
|
||||
uint8_t* curr_bitmap;
|
||||
int sector_count;
|
||||
int curr_block;
|
||||
} MVHDSectorBitmap;
|
||||
|
||||
typedef struct MVHDFooter {
|
||||
uint8_t cookie[8];
|
||||
uint32_t features;
|
||||
uint32_t fi_fmt_vers;
|
||||
uint64_t data_offset;
|
||||
uint32_t timestamp;
|
||||
uint8_t cr_app[4];
|
||||
uint32_t cr_vers;
|
||||
uint8_t cr_host_os[4];
|
||||
uint64_t orig_sz;
|
||||
uint64_t curr_sz;
|
||||
struct {
|
||||
uint16_t cyl;
|
||||
uint8_t heads;
|
||||
uint8_t spt;
|
||||
} geom;
|
||||
uint32_t disk_type;
|
||||
uint32_t checksum;
|
||||
uint8_t uuid[16];
|
||||
uint8_t saved_st;
|
||||
uint8_t reserved[427];
|
||||
} MVHDFooter;
|
||||
|
||||
typedef struct MVHDSparseHeader {
|
||||
uint8_t cookie[8];
|
||||
uint64_t data_offset;
|
||||
uint64_t bat_offset;
|
||||
uint32_t head_vers;
|
||||
uint32_t max_bat_ent;
|
||||
uint32_t block_sz;
|
||||
uint32_t checksum;
|
||||
uint8_t par_uuid[16];
|
||||
uint32_t par_timestamp;
|
||||
uint32_t reserved_1;
|
||||
uint8_t par_utf16_name[512];
|
||||
struct {
|
||||
uint32_t plat_code;
|
||||
uint32_t plat_data_space;
|
||||
uint32_t plat_data_len;
|
||||
uint32_t reserved;
|
||||
uint64_t plat_data_offset;
|
||||
} par_loc_entry[8];
|
||||
uint8_t reserved_2[256];
|
||||
} MVHDSparseHeader;
|
||||
|
||||
struct MVHDMeta {
|
||||
FILE* f;
|
||||
bool readonly;
|
||||
char filename[MVHD_MAX_PATH_BYTES];
|
||||
struct MVHDMeta* parent;
|
||||
MVHDFooter footer;
|
||||
MVHDSparseHeader sparse;
|
||||
uint32_t* block_offset;
|
||||
int sect_per_block;
|
||||
MVHDSectorBitmap bitmap;
|
||||
int (*read_sectors)(struct MVHDMeta*, uint32_t, int, void*);
|
||||
int (*write_sectors)(struct MVHDMeta*, uint32_t, int, void*);
|
||||
struct {
|
||||
uint8_t* zero_data;
|
||||
int sector_count;
|
||||
} format_buffer;
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Functions to deal with endian issues
|
||||
*/
|
||||
uint16_t mvhd_from_be16(uint16_t val);
|
||||
uint32_t mvhd_from_be32(uint32_t val);
|
||||
uint64_t mvhd_from_be64(uint64_t val);
|
||||
uint16_t mvhd_to_be16(uint16_t val);
|
||||
uint32_t mvhd_to_be32(uint32_t val);
|
||||
uint64_t mvhd_to_be64(uint64_t val);
|
||||
|
||||
/**
|
||||
* \brief Check if provided buffer begins with the string "conectix"
|
||||
*
|
||||
* \param [in] buffer The buffer to compare. Must be at least 8 bytes in length
|
||||
*
|
||||
* \return true if the buffer begins with "conectix"
|
||||
* \return false if the buffer does not begin with "conectix"
|
||||
*/
|
||||
bool mvhd_is_conectix_str(const void* buffer);
|
||||
|
||||
/**
|
||||
* \brief Generate a raw 16 byte UUID
|
||||
*
|
||||
* \param [out] uuid A 16 byte buffer in which the generated UUID will be stored to
|
||||
*/
|
||||
void mvhd_generate_uuid(uint8_t *uuid);
|
||||
|
||||
/**
|
||||
* \brief Calculate a VHD formatted timestamp from the current time
|
||||
*/
|
||||
uint32_t vhd_calc_timestamp(void);
|
||||
|
||||
/**
|
||||
* \brief Convert an epoch timestamp to a VHD timestamp
|
||||
*
|
||||
* \param [in] ts epoch timestamp to convert.
|
||||
*
|
||||
* \return The adjusted timestamp, or 0 if the input timestamp is
|
||||
* earlier that 1 Janurary 2000
|
||||
*/
|
||||
uint32_t mvhd_epoch_to_vhd_ts(time_t ts);
|
||||
|
||||
/**
|
||||
* \brief Return the created time from a VHD image
|
||||
*
|
||||
* \param [in] vhdm Pointer to the MiniVHD metadata structure
|
||||
*
|
||||
* \return The created time, as a Unix timestamp
|
||||
*/
|
||||
time_t vhd_get_created_time(struct MVHDMeta *vhdm);
|
||||
|
||||
/**
|
||||
* \brief Cross platform, unicode filepath opening
|
||||
*
|
||||
* This function accounts for the fact that fopen() handles file paths differently compared to other
|
||||
* operating systems. Windows version of fopen() will not handle multi byte encoded text like UTF-8.
|
||||
*
|
||||
* Unicode filepath support on Windows requires using the _wfopen() function, which expects UTF-16LE
|
||||
* encoded path and modestring.
|
||||
*
|
||||
* \param [in] path The filepath to open as a UTF-8 string
|
||||
* \param [in] mode The mode string to use (eg: "rb+"")
|
||||
* \param [out] err The error value, if an error occurrs
|
||||
*
|
||||
* \return a FILE pointer if successful, NULL otherwise. If NULL, check the value of err
|
||||
*/
|
||||
FILE* mvhd_fopen(const char* path, const char* mode, int* err);
|
||||
|
||||
void mvhd_set_encoding_err(int encoding_retval, int* err);
|
||||
|
||||
/**
|
||||
* \brief Generate VHD footer checksum
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
uint32_t mvhd_gen_footer_checksum(MVHDFooter* footer);
|
||||
|
||||
/**
|
||||
* \brief Generate VHD sparse header checksum
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
uint32_t mvhd_gen_sparse_checksum(MVHDSparseHeader* header);
|
||||
|
||||
uint32_t mvhd_crc32_for_byte(uint32_t r);
|
||||
|
||||
/**
|
||||
* \brief Get current position in file stream
|
||||
*
|
||||
* This is a portable version of the POSIX ftello64(). *
|
||||
*/
|
||||
int64_t mvhd_ftello64(FILE* stream);
|
||||
|
||||
/**
|
||||
* \brief Reposition the file stream's position
|
||||
*
|
||||
* This is a portable version of the POSIX fseeko64(). *
|
||||
*/
|
||||
int mvhd_fseeko64(FILE* stream, int64_t offset, int origin);
|
||||
|
||||
/**
|
||||
* \brief Calculate the CRC32 of a data buffer.
|
||||
*
|
||||
* This function can be used for verifying data integrity.
|
||||
*
|
||||
* \param [in] data The data buffer
|
||||
* \param [in] n_bytes The size of the data buffer in bytes
|
||||
*
|
||||
* \return The CRC32 of the data buffer
|
||||
*/
|
||||
uint32_t mvhd_crc32(const void* data, size_t n_bytes);
|
||||
|
||||
/**
|
||||
* \brief Calculate the file modification timestamp.
|
||||
*
|
||||
* This function is primarily to help protect differencing VHD's
|
||||
*
|
||||
* \param [in] path the UTF-8 file path
|
||||
* \param [out] err The error value, if an error occurrs
|
||||
*
|
||||
* \return The file modified timestamp, in VHD compatible timestamp.
|
||||
* 'err' will be set to non-zero on error
|
||||
*/
|
||||
uint32_t mvhd_file_mod_timestamp(const char* path, int *err);
|
||||
|
||||
struct MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, uint64_t size_in_bytes, MVHDGeom* geom, int* err, mvhd_progress_callback progress_callback);
|
||||
|
||||
/**
|
||||
* \brief Write zero filled sectors to file.
|
||||
*
|
||||
* Note, the caller should set the file position before calling this
|
||||
* function for correct operation.
|
||||
*
|
||||
* \param [in] f File to write sectors to
|
||||
* \param [in] sector_count The number of sectors to write
|
||||
*/
|
||||
void mvhd_write_empty_sectors(FILE* f, int sector_count);
|
||||
|
||||
/**
|
||||
* \brief Read a fixed VHD image
|
||||
*
|
||||
* Fixed VHD images are essentially raw image files with a footer tacked on
|
||||
* the end. They are therefore straightforward to write
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset Sector offset to read from
|
||||
* \param [in] num_sectors The desired number of sectors to read
|
||||
* \param [out] out_buff An output buffer to store read sectors. Must be
|
||||
* large enough to hold num_sectors worth of sectors.
|
||||
*
|
||||
* \retval 0 num_sectors were read from file
|
||||
* \retval >0 < num_sectors were read from file
|
||||
*/
|
||||
int mvhd_fixed_read(struct MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff);
|
||||
|
||||
/**
|
||||
* \brief Read a sparse VHD image
|
||||
*
|
||||
* Sparse, or dynamic images are VHD images that grow as data is written to them.
|
||||
*
|
||||
* This function implements the logic to read sectors from the file, taking into
|
||||
* account the fact that blocks may be stored on disk in any order, and that the
|
||||
* read could cross block boundaries.
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset Sector offset to read from
|
||||
* \param [in] num_sectors The desired number of sectors to read
|
||||
* \param [out] out_buff An output buffer to store read sectors. Must be
|
||||
* large enough to hold num_sectors worth of sectors.
|
||||
*
|
||||
* \retval 0 num_sectors were read from file
|
||||
* \retval >0 < num_sectors were read from file
|
||||
*/
|
||||
int mvhd_sparse_read(struct MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff);
|
||||
|
||||
/**
|
||||
* \brief Read a differencing VHD image
|
||||
*
|
||||
* Differencing images are a variant of a sparse image. They contain the grow-on-demand
|
||||
* properties of sparse images, but also reference a parent image. Data is read from the
|
||||
* child image only if it is newer than the data stored in the parent image.
|
||||
*
|
||||
* This function implements the logic to read sectors from the child, or a parent image.
|
||||
* Differencing images may have a differencing image as a parent, creating a chain of images.
|
||||
* There is no theoretical chain length limit, although I do not consider long chains to be
|
||||
* advisable. Verifying the parent-child relationship is not very robust.
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset Sector offset to read from
|
||||
* \param [in] num_sectors The desired number of sectors to read
|
||||
* \param [out] out_buff An output buffer to store read sectors. Must be
|
||||
* large enough to hold num_sectors worth of sectors.
|
||||
*
|
||||
* \retval 0 num_sectors were read from file
|
||||
* \retval >0 < num_sectors were read from file
|
||||
*/
|
||||
int mvhd_diff_read(struct MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff);
|
||||
|
||||
/**
|
||||
* \brief Write to a fixed VHD image
|
||||
*
|
||||
* Fixed VHD images are essentially raw image files with a footer tacked on
|
||||
* the end. They are therefore straightforward to write
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset Sector offset to write to
|
||||
* \param [in] num_sectors The desired number of sectors to write
|
||||
* \param [in] in_buff A source buffer to write sectors from. Must be
|
||||
* large enough to hold num_sectors worth of sectors.
|
||||
*
|
||||
* \retval 0 num_sectors were written to file
|
||||
* \retval >0 < num_sectors were written to file
|
||||
*/
|
||||
int mvhd_fixed_write(struct MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff);
|
||||
|
||||
/**
|
||||
* \brief Write to a sparse or differencing VHD image
|
||||
*
|
||||
* Sparse, or dynamic images are VHD images that grow as data is written to them.
|
||||
*
|
||||
* Differencing images are a variant of a sparse image. They contain the grow-on-demand
|
||||
* properties of sparse images, but also reference a parent image. Data is always written
|
||||
* to the child image. This makes writing to differencing images essentially identical to
|
||||
* writing to sparse images, hence they use the same function.
|
||||
*
|
||||
* This function implements the logic to write sectors to the file, taking into
|
||||
* account the fact that blocks may be stored on disk in any order, and that the
|
||||
* write operation could cross block boundaries.
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset Sector offset to write to
|
||||
* \param [in] num_sectors The desired number of sectors to write
|
||||
* \param [in] in_buff A source buffer to write sectors from. Must be
|
||||
* large enough to hold num_sectors worth of sectors.
|
||||
*
|
||||
* \retval 0 num_sectors were written to file
|
||||
* \retval >0 < num_sectors were written to file
|
||||
*/
|
||||
int mvhd_sparse_diff_write(struct MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff);
|
||||
|
||||
/**
|
||||
* \brief A no-op function to "write" to read-only VHD images
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset Sector offset to write to
|
||||
* \param [in] num_sectors The desired number of sectors to write
|
||||
* \param [in] in_buff A source buffer to write sectors from. Must be
|
||||
* large enough to hold num_sectors worth of sectors.
|
||||
*
|
||||
* \retval 0 num_sectors were written to file
|
||||
* \retval >0 < num_sectors were written to file
|
||||
*/
|
||||
int mvhd_noop_write(struct MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff);
|
||||
|
||||
/**
|
||||
* \brief Save the contents of a VHD footer from a buffer to a struct
|
||||
*
|
||||
* \param [out] footer save contents of buffer into footer
|
||||
* \param [in] buffer VHD footer in raw bytes
|
||||
*/
|
||||
void mvhd_buffer_to_footer(MVHDFooter* footer, uint8_t* buffer);
|
||||
|
||||
/**
|
||||
* \brief Save the contents of a VHD sparse header from a buffer to a struct
|
||||
*
|
||||
* \param [out] header save contents of buffer into header
|
||||
* \param [in] buffer VHD header in raw bytes
|
||||
*/
|
||||
void mvhd_buffer_to_header(MVHDSparseHeader* header, uint8_t* buffer);
|
||||
|
||||
/**
|
||||
* \brief Save the contents of a VHD footer struct to a buffer
|
||||
*
|
||||
* \param [in] footer save contents of struct into buffer
|
||||
* \param [out] buffer VHD footer in raw bytes
|
||||
*/
|
||||
void mvhd_footer_to_buffer(MVHDFooter* footer, uint8_t* buffer);
|
||||
|
||||
/**
|
||||
* \brief Save the contents of a VHD sparse header struct to a buffer
|
||||
*
|
||||
* \param [in] header save contents of struct into buffer
|
||||
* \param [out] buffer VHD sparse header in raw bytes
|
||||
*/
|
||||
void mvhd_header_to_buffer(MVHDSparseHeader* header, uint8_t* buffer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*MINIVHD_INTERNAL_H*/
|
||||
@@ -1,12 +0,0 @@
|
||||
#ifndef LIBXML2_ENCODING_H
|
||||
#define LIBXML2_ENCODING_H
|
||||
|
||||
#include <stdint.h>
|
||||
typedef uint16_t mvhd_utf16;
|
||||
|
||||
void xmlEncodingInit(void);
|
||||
int UTF16LEToUTF8(unsigned char* out, int *outlen, const unsigned char* inb, int *inlenb);
|
||||
int UTF8ToUTF16LE(unsigned char* outb, int *outlen, const unsigned char* in, int *inlen);
|
||||
int UTF16BEToUTF8(unsigned char* out, int *outlen, const unsigned char* inb, int *inlenb);
|
||||
int UTF8ToUTF16BE(unsigned char* outb, int *outlen, const unsigned char* in, int *inlen);
|
||||
#endif
|
||||
@@ -1,66 +1,105 @@
|
||||
/**
|
||||
* \file
|
||||
* \brief VHD management functions (open, close, read write etc)
|
||||
/*
|
||||
* MiniVHD Minimalist VHD implementation in C.
|
||||
*
|
||||
* This file is part of the MiniVHD Project.
|
||||
*
|
||||
* VHD management functions (open, close, read write etc)
|
||||
*
|
||||
* Version: @(#)manage.c 1.0.4 2021/04/16
|
||||
*
|
||||
* Authors: Sherman Perry, <shermperry@gmail.com>
|
||||
* Fred N. van Kempen, <waltje@varcem.com>
|
||||
*
|
||||
* Copyright 2019-2021 Sherman Perry.
|
||||
* Copyright 2021 Fred N. van Kempen.
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documenta-
|
||||
* tion files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall
|
||||
* be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF O R IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "cwalk.h"
|
||||
#include "libxml2_encoding.h"
|
||||
#include "minivhd_internal.h"
|
||||
#include "minivhd_io.h"
|
||||
#include "minivhd_util.h"
|
||||
#include "minivhd_struct_rw.h"
|
||||
#include <time.h>
|
||||
#include "minivhd.h"
|
||||
#include "internal.h"
|
||||
#include "version.h"
|
||||
#include "cwalk.h"
|
||||
#include "xml2_encoding.h"
|
||||
|
||||
|
||||
int mvhd_errno = 0;
|
||||
static char tmp_open_path[MVHD_MAX_PATH_BYTES] = {0};
|
||||
struct MVHDPaths {
|
||||
char dir_path[MVHD_MAX_PATH_BYTES];
|
||||
char file_name[MVHD_MAX_PATH_BYTES];
|
||||
char w2ku_path[MVHD_MAX_PATH_BYTES];
|
||||
char w2ru_path[MVHD_MAX_PATH_BYTES];
|
||||
char joined_path[MVHD_MAX_PATH_BYTES];
|
||||
char dir_path[MVHD_MAX_PATH_BYTES];
|
||||
char file_name[MVHD_MAX_PATH_BYTES];
|
||||
char w2ku_path[MVHD_MAX_PATH_BYTES];
|
||||
char w2ru_path[MVHD_MAX_PATH_BYTES];
|
||||
char joined_path[MVHD_MAX_PATH_BYTES];
|
||||
uint16_t tmp_src_path[MVHD_MAX_PATH_CHARS];
|
||||
};
|
||||
|
||||
static void mvhd_read_footer(MVHDMeta* vhdm);
|
||||
static void mvhd_read_sparse_header(MVHDMeta* vhdm);
|
||||
static bool mvhd_footer_checksum_valid(MVHDMeta* vhdm);
|
||||
static bool mvhd_sparse_checksum_valid(MVHDMeta* vhdm);
|
||||
static int mvhd_read_bat(MVHDMeta *vhdm, MVHDError* err);
|
||||
static void mvhd_calc_sparse_values(MVHDMeta* vhdm);
|
||||
static int mvhd_init_sector_bitmap(MVHDMeta* vhdm, MVHDError* err);
|
||||
|
||||
int mvhd_errno = 0;
|
||||
|
||||
|
||||
static char tmp_open_path[MVHD_MAX_PATH_BYTES] = {0};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Populate data stuctures with content from a VHD footer
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
static void mvhd_read_footer(MVHDMeta* vhdm) {
|
||||
static void
|
||||
read_footer(MVHDMeta* vhdm)
|
||||
{
|
||||
uint8_t buffer[MVHD_FOOTER_SIZE];
|
||||
|
||||
mvhd_fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END);
|
||||
(void) !fread(buffer, sizeof buffer, 1, vhdm->f);
|
||||
mvhd_buffer_to_footer(&vhdm->footer, buffer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Populate data stuctures with content from a VHD sparse header
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
static void mvhd_read_sparse_header(MVHDMeta* vhdm) {
|
||||
static void
|
||||
read_sparse_header(MVHDMeta* vhdm)
|
||||
{
|
||||
uint8_t buffer[MVHD_SPARSE_SIZE];
|
||||
|
||||
mvhd_fseeko64(vhdm->f, vhdm->footer.data_offset, SEEK_SET);
|
||||
(void) !fread(buffer, sizeof buffer, 1, vhdm->f);
|
||||
mvhd_buffer_to_header(&vhdm->sparse, buffer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Validate VHD footer checksum
|
||||
*
|
||||
@@ -68,10 +107,13 @@ static void mvhd_read_sparse_header(MVHDMeta* vhdm) {
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
static bool mvhd_footer_checksum_valid(MVHDMeta* vhdm) {
|
||||
static bool
|
||||
footer_checksum_valid(MVHDMeta* vhdm)
|
||||
{
|
||||
return vhdm->footer.checksum == mvhd_gen_footer_checksum(&vhdm->footer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Validate VHD sparse header checksum
|
||||
*
|
||||
@@ -79,10 +121,13 @@ static bool mvhd_footer_checksum_valid(MVHDMeta* vhdm) {
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
static bool mvhd_sparse_checksum_valid(MVHDMeta* vhdm) {
|
||||
static bool
|
||||
sparse_checksum_valid(MVHDMeta* vhdm)
|
||||
{
|
||||
return vhdm->sparse.checksum == mvhd_gen_sparse_checksum(&vhdm->sparse);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Read BAT into MiniVHD data structure
|
||||
*
|
||||
@@ -96,13 +141,17 @@ static bool mvhd_sparse_checksum_valid(MVHDMeta* vhdm) {
|
||||
* \retval -1 if an error occurrs. Check value of err in this case
|
||||
* \retval 0 if the function call succeeds
|
||||
*/
|
||||
static int mvhd_read_bat(MVHDMeta *vhdm, MVHDError* err) {
|
||||
static int
|
||||
read_bat(MVHDMeta *vhdm, MVHDError* err)
|
||||
{
|
||||
vhdm->block_offset = calloc(vhdm->sparse.max_bat_ent, sizeof *vhdm->block_offset);
|
||||
if (vhdm->block_offset == NULL) {
|
||||
*err = MVHD_ERR_MEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
mvhd_fseeko64(vhdm->f, vhdm->sparse.bat_offset, SEEK_SET);
|
||||
|
||||
for (uint32_t i = 0; i < vhdm->sparse.max_bat_ent; i++) {
|
||||
(void) !fread(&vhdm->block_offset[i], sizeof *vhdm->block_offset, 1, vhdm->f);
|
||||
vhdm->block_offset[i] = mvhd_from_be32(vhdm->block_offset[i]);
|
||||
@@ -110,20 +159,25 @@ static int mvhd_read_bat(MVHDMeta *vhdm, MVHDError* err) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Perform a one-time calculation of some sparse VHD values
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
static void mvhd_calc_sparse_values(MVHDMeta* vhdm) {
|
||||
static void
|
||||
calc_sparse_values(MVHDMeta* vhdm)
|
||||
{
|
||||
vhdm->sect_per_block = vhdm->sparse.block_sz / MVHD_SECTOR_SIZE;
|
||||
int bm_bytes = vhdm->sect_per_block / 8;
|
||||
vhdm->bitmap.sector_count = bm_bytes / MVHD_SECTOR_SIZE;
|
||||
|
||||
if (bm_bytes % MVHD_SECTOR_SIZE > 0) {
|
||||
vhdm->bitmap.sector_count++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Allocate memory for a sector bitmap.
|
||||
*
|
||||
@@ -137,16 +191,21 @@ static void mvhd_calc_sparse_values(MVHDMeta* vhdm) {
|
||||
* \retval -1 if an error occurrs. Check value of err in this case
|
||||
* \retval 0 if the function call succeeds
|
||||
*/
|
||||
static int mvhd_init_sector_bitmap(MVHDMeta* vhdm, MVHDError* err) {
|
||||
static int
|
||||
init_sector_bitmap(MVHDMeta* vhdm, MVHDError* err)
|
||||
{
|
||||
vhdm->bitmap.curr_bitmap = calloc(vhdm->bitmap.sector_count, MVHD_SECTOR_SIZE);
|
||||
if (vhdm->bitmap.curr_bitmap == NULL) {
|
||||
*err = MVHD_ERR_MEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
vhdm->bitmap.curr_block = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Check if the path for a given platform code exists
|
||||
*
|
||||
@@ -163,13 +222,19 @@ static int mvhd_init_sector_bitmap(MVHDMeta* vhdm, MVHDError* err) {
|
||||
* \retval true if a file is found
|
||||
* \retval false if a file is not found
|
||||
*/
|
||||
static bool mvhd_parent_path_exists(struct MVHDPaths* paths, uint32_t plat_code) {
|
||||
memset(paths->joined_path, 0, sizeof paths->joined_path);
|
||||
static bool
|
||||
mvhd_parent_path_exists(struct MVHDPaths* paths, uint32_t plat_code)
|
||||
{
|
||||
FILE* f;
|
||||
int cwk_ret, ferr;
|
||||
enum cwk_path_style style = cwk_path_guess_style((const char*)paths->dir_path);
|
||||
int ferr;
|
||||
size_t cwk_ret;
|
||||
enum cwk_path_style style;
|
||||
|
||||
memset(paths->joined_path, 0, sizeof paths->joined_path);
|
||||
style = cwk_path_guess_style((const char*)paths->dir_path);
|
||||
cwk_path_set_style(style);
|
||||
cwk_ret = 1;
|
||||
|
||||
if (plat_code == MVHD_DIF_LOC_W2RU && *paths->w2ru_path) {
|
||||
cwk_ret = cwk_path_join((const char*)paths->dir_path, (const char*)paths->w2ru_path, paths->joined_path, sizeof paths->joined_path);
|
||||
} else if (plat_code == MVHD_DIF_LOC_W2KU && *paths->w2ku_path) {
|
||||
@@ -181,6 +246,7 @@ static bool mvhd_parent_path_exists(struct MVHDPaths* paths, uint32_t plat_code)
|
||||
if (cwk_ret > MVHD_MAX_PATH_BYTES) {
|
||||
return false;
|
||||
}
|
||||
|
||||
f = mvhd_fopen((const char*)paths->joined_path, "rb", &ferr);
|
||||
if (f != NULL) {
|
||||
/* We found a file at the requested path! */
|
||||
@@ -188,11 +254,12 @@ static bool mvhd_parent_path_exists(struct MVHDPaths* paths, uint32_t plat_code)
|
||||
tmp_open_path[sizeof tmp_open_path - 1] = '\0';
|
||||
fclose(f);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief attempt to obtain a file path to a file that may be a valid VHD image
|
||||
*
|
||||
@@ -208,27 +275,33 @@ static bool mvhd_parent_path_exists(struct MVHDPaths* paths, uint32_t plat_code)
|
||||
* \return a pointer to the global string `tmp_open_path`, or NULL if a path could
|
||||
* not be found, or some error occurred
|
||||
*/
|
||||
static char* mvhd_get_diff_parent_path(MVHDMeta* vhdm, int* err) {
|
||||
static char*
|
||||
get_diff_parent_path(MVHDMeta* vhdm, int* err)
|
||||
{
|
||||
int utf_outlen, utf_inlen, utf_ret;
|
||||
char* par_fp = NULL;
|
||||
char *par_fp = NULL;
|
||||
struct MVHDPaths *paths;
|
||||
size_t dirlen;
|
||||
|
||||
/* We can't resolve relative paths if we don't have an absolute
|
||||
path to work with */
|
||||
if (!cwk_path_is_absolute((const char*)vhdm->filename)) {
|
||||
*err = MVHD_ERR_PATH_REL;
|
||||
goto end;
|
||||
}
|
||||
struct MVHDPaths* paths = calloc(1, sizeof *paths);
|
||||
|
||||
paths = calloc(1, sizeof *paths);
|
||||
if (paths == NULL) {
|
||||
*err = MVHD_ERR_MEM;
|
||||
goto end;
|
||||
}
|
||||
size_t dirlen;
|
||||
cwk_path_get_dirname((const char*)vhdm->filename, &dirlen);
|
||||
if (dirlen >= sizeof paths->dir_path) {
|
||||
*err = MVHD_ERR_PATH_LEN;
|
||||
goto paths_cleanup;
|
||||
}
|
||||
memcpy(paths->dir_path, vhdm->filename, dirlen);
|
||||
|
||||
/* Get the filename field from the sparse header. */
|
||||
utf_outlen = (int)sizeof paths->file_name;
|
||||
utf_inlen = (int)sizeof vhdm->sparse.par_utf16_name;
|
||||
@@ -237,8 +310,10 @@ static char* mvhd_get_diff_parent_path(MVHDMeta* vhdm, int* err) {
|
||||
mvhd_set_encoding_err(utf_ret, err);
|
||||
goto paths_cleanup;
|
||||
}
|
||||
|
||||
/* Now read the parent locator entries, both relative and absolute, if they exist */
|
||||
unsigned char* loc_path;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
utf_outlen = MVHD_MAX_PATH_BYTES - 1;
|
||||
if (vhdm->sparse.par_loc_entry[i].plat_code == MVHD_DIF_LOC_W2RU) {
|
||||
@@ -248,6 +323,7 @@ static char* mvhd_get_diff_parent_path(MVHDMeta* vhdm, int* err) {
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
utf_inlen = vhdm->sparse.par_loc_entry[i].plat_data_len;
|
||||
if (utf_inlen > MVHD_MAX_PATH_BYTES) {
|
||||
*err = MVHD_ERR_PATH_LEN;
|
||||
@@ -255,6 +331,7 @@ static char* mvhd_get_diff_parent_path(MVHDMeta* vhdm, int* err) {
|
||||
}
|
||||
mvhd_fseeko64(vhdm->f, vhdm->sparse.par_loc_entry[i].plat_data_offset, SEEK_SET);
|
||||
(void) !fread(paths->tmp_src_path, sizeof (uint8_t), utf_inlen, vhdm->f);
|
||||
|
||||
/* Note, the W2*u parent locators are UTF-16LE, unlike the filename field previously obtained,
|
||||
which is UTF-16BE */
|
||||
utf_ret = UTF16LEToUTF8(loc_path, &utf_outlen, (const unsigned char*)paths->tmp_src_path, &utf_inlen);
|
||||
@@ -263,22 +340,26 @@ static char* mvhd_get_diff_parent_path(MVHDMeta* vhdm, int* err) {
|
||||
goto paths_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* We have paths in UTF-8. We should have enough info to try and find the parent VHD */
|
||||
/* Does the relative path exist? */
|
||||
if (mvhd_parent_path_exists(paths, MVHD_DIF_LOC_W2RU)) {
|
||||
par_fp = tmp_open_path;
|
||||
goto paths_cleanup;
|
||||
}
|
||||
|
||||
/* What about trying the child directory? */
|
||||
if (mvhd_parent_path_exists(paths, 0)) {
|
||||
par_fp = tmp_open_path;
|
||||
goto paths_cleanup;
|
||||
}
|
||||
|
||||
/* Well, all else fails, try the stored absolute path, if it exists */
|
||||
if (mvhd_parent_path_exists(paths, MVHD_DIF_LOC_W2KU)) {
|
||||
par_fp = tmp_open_path;
|
||||
goto paths_cleanup;
|
||||
}
|
||||
|
||||
/* If we reach this point, we could not find a path with a valid file */
|
||||
par_fp = NULL;
|
||||
*err = MVHD_ERR_PAR_NOT_FOUND;
|
||||
@@ -286,10 +367,12 @@ static char* mvhd_get_diff_parent_path(MVHDMeta* vhdm, int* err) {
|
||||
paths_cleanup:
|
||||
free(paths);
|
||||
paths = NULL;
|
||||
|
||||
end:
|
||||
return par_fp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Attach the read/write function pointers to read/write functions
|
||||
*
|
||||
@@ -298,44 +381,90 @@ end:
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
static void mvhd_assign_io_funcs(MVHDMeta* vhdm) {
|
||||
static void
|
||||
assign_io_funcs(MVHDMeta* vhdm)
|
||||
{
|
||||
switch (vhdm->footer.disk_type) {
|
||||
case MVHD_TYPE_FIXED:
|
||||
vhdm->read_sectors = mvhd_fixed_read;
|
||||
vhdm->write_sectors = mvhd_fixed_write;
|
||||
break;
|
||||
case MVHD_TYPE_DYNAMIC:
|
||||
vhdm->read_sectors = mvhd_sparse_read;
|
||||
vhdm->write_sectors = mvhd_sparse_diff_write;
|
||||
break;
|
||||
case MVHD_TYPE_DIFF:
|
||||
vhdm->read_sectors = mvhd_diff_read;
|
||||
vhdm->write_sectors = mvhd_sparse_diff_write;
|
||||
break;
|
||||
case MVHD_TYPE_FIXED:
|
||||
vhdm->read_sectors = mvhd_fixed_read;
|
||||
vhdm->write_sectors = mvhd_fixed_write;
|
||||
break;
|
||||
|
||||
case MVHD_TYPE_DYNAMIC:
|
||||
vhdm->read_sectors = mvhd_sparse_read;
|
||||
vhdm->write_sectors = mvhd_sparse_diff_write;
|
||||
break;
|
||||
|
||||
case MVHD_TYPE_DIFF:
|
||||
vhdm->read_sectors = mvhd_diff_read;
|
||||
vhdm->write_sectors = mvhd_sparse_diff_write;
|
||||
break;
|
||||
}
|
||||
if (vhdm->readonly) {
|
||||
|
||||
if (vhdm->readonly)
|
||||
vhdm->write_sectors = mvhd_noop_write;
|
||||
}
|
||||
}
|
||||
|
||||
bool mvhd_file_is_vhd(FILE* f) {
|
||||
if (f) {
|
||||
uint8_t con_str[8];
|
||||
mvhd_fseeko64(f, -MVHD_FOOTER_SIZE, SEEK_END);
|
||||
(void) !fread(con_str, sizeof con_str, 1, f);
|
||||
return mvhd_is_conectix_str(con_str);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the library version as a string
|
||||
*/
|
||||
MVHDAPI const char *
|
||||
mvhd_version(void)
|
||||
{
|
||||
return LIB_VERSION_4;
|
||||
}
|
||||
|
||||
MVHDGeom mvhd_calculate_geometry(uint64_t size) {
|
||||
|
||||
/**
|
||||
* \brief Return the library version as a number
|
||||
*/
|
||||
MVHDAPI uint32_t
|
||||
mvhd_version_id(void)
|
||||
{
|
||||
return (LIB_VER_MAJOR << 24) | (LIB_VER_MINOR << 16) |
|
||||
(LIB_VER_REV << 16) | LIB_VER_PATCH;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief A simple test to see if a given file is a VHD
|
||||
*
|
||||
* \param [in] f file to test
|
||||
*
|
||||
* \retval 1 if f is a VHD
|
||||
* \retval 0 if f is not a VHD
|
||||
*/
|
||||
MVHDAPI int
|
||||
mvhd_file_is_vhd(FILE* f)
|
||||
{
|
||||
uint8_t con_str[8];
|
||||
|
||||
if (f == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
mvhd_fseeko64(f, -MVHD_FOOTER_SIZE, SEEK_END);
|
||||
fread(con_str, sizeof con_str, 1, f);
|
||||
if (mvhd_is_conectix_str(con_str)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
MVHDAPI MVHDGeom
|
||||
mvhd_calculate_geometry(uint64_t size)
|
||||
{
|
||||
MVHDGeom chs;
|
||||
uint32_t ts = (uint32_t)(size / MVHD_SECTOR_SIZE);
|
||||
uint32_t spt, heads, cyl, cth;
|
||||
|
||||
if (ts > 65535 * 16 * 255) {
|
||||
ts = 65535 * 16 * 255;
|
||||
}
|
||||
|
||||
if (ts >= 65535 * 16 * 63) {
|
||||
spt = 255;
|
||||
heads = 16;
|
||||
@@ -358,77 +487,95 @@ MVHDGeom mvhd_calculate_geometry(uint64_t size) {
|
||||
cth = ts / spt;
|
||||
}
|
||||
}
|
||||
|
||||
cyl = cth / heads;
|
||||
chs.heads = heads;
|
||||
chs.spt = spt;
|
||||
chs.cyl = cyl;
|
||||
|
||||
return chs;
|
||||
}
|
||||
|
||||
MVHDMeta* mvhd_open(const char* path, bool readonly, int* err) {
|
||||
|
||||
MVHDAPI MVHDMeta*
|
||||
mvhd_open(const char* path, int readonly, int* err)
|
||||
{
|
||||
MVHDError open_err;
|
||||
|
||||
MVHDMeta *vhdm = calloc(sizeof *vhdm, 1);
|
||||
if (vhdm == NULL) {
|
||||
*err = MVHD_ERR_MEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (strlen(path) >= sizeof vhdm->filename) {
|
||||
*err = MVHD_ERR_PATH_LEN;
|
||||
goto cleanup_vhdm;
|
||||
}
|
||||
|
||||
//This is safe, as we've just checked for potential overflow above
|
||||
strcpy(vhdm->filename, path);
|
||||
vhdm->f = readonly ? mvhd_fopen((const char*)vhdm->filename, "rb", err) : mvhd_fopen((const char*)vhdm->filename, "rb+", err);
|
||||
|
||||
if (readonly) {
|
||||
vhdm->f = mvhd_fopen((const char*)vhdm->filename, "rb", err);
|
||||
} else {
|
||||
vhdm->f = mvhd_fopen((const char*)vhdm->filename, "rb+", err);
|
||||
}
|
||||
if (vhdm->f == NULL) {
|
||||
/* note, mvhd_fopen sets err for us */
|
||||
goto cleanup_vhdm;
|
||||
}
|
||||
vhdm->readonly = readonly;
|
||||
|
||||
if (!mvhd_file_is_vhd(vhdm->f)) {
|
||||
*err = MVHD_ERR_NOT_VHD;
|
||||
goto cleanup_file;
|
||||
}
|
||||
mvhd_read_footer(vhdm);
|
||||
if (!mvhd_footer_checksum_valid(vhdm)) {
|
||||
|
||||
read_footer(vhdm);
|
||||
if (!footer_checksum_valid(vhdm)) {
|
||||
*err = MVHD_ERR_FOOTER_CHECKSUM;
|
||||
goto cleanup_file;
|
||||
}
|
||||
if (vhdm->footer.disk_type == MVHD_TYPE_DIFF || vhdm->footer.disk_type == MVHD_TYPE_DYNAMIC) {
|
||||
mvhd_read_sparse_header(vhdm);
|
||||
if (!mvhd_sparse_checksum_valid(vhdm)) {
|
||||
read_sparse_header(vhdm);
|
||||
if (!sparse_checksum_valid(vhdm)) {
|
||||
*err = MVHD_ERR_SPARSE_CHECKSUM;
|
||||
goto cleanup_file;
|
||||
}
|
||||
if (mvhd_read_bat(vhdm, &open_err) == -1) {
|
||||
if (read_bat(vhdm, &open_err) == -1) {
|
||||
*err = open_err;
|
||||
goto cleanup_file;
|
||||
}
|
||||
mvhd_calc_sparse_values(vhdm);
|
||||
if (mvhd_init_sector_bitmap(vhdm, &open_err) == -1) {
|
||||
calc_sparse_values(vhdm);
|
||||
if (init_sector_bitmap(vhdm, &open_err) == -1) {
|
||||
*err = open_err;
|
||||
goto cleanup_bat;
|
||||
}
|
||||
|
||||
} else if (vhdm->footer.disk_type != MVHD_TYPE_FIXED) {
|
||||
*err = MVHD_ERR_TYPE;
|
||||
goto cleanup_bitmap;
|
||||
}
|
||||
mvhd_assign_io_funcs(vhdm);
|
||||
assign_io_funcs(vhdm);
|
||||
|
||||
vhdm->format_buffer.zero_data = calloc(64, MVHD_SECTOR_SIZE);
|
||||
if (vhdm->format_buffer.zero_data == NULL) {
|
||||
*err = MVHD_ERR_MEM;
|
||||
goto cleanup_bitmap;
|
||||
}
|
||||
|
||||
vhdm->format_buffer.sector_count = 64;
|
||||
if (vhdm->footer.disk_type == MVHD_TYPE_DIFF) {
|
||||
char* par_path = mvhd_get_diff_parent_path(vhdm, err);
|
||||
char* par_path = get_diff_parent_path(vhdm, err);
|
||||
if (par_path == NULL) {
|
||||
goto cleanup_format_buff;
|
||||
}
|
||||
|
||||
uint32_t par_mod_ts = mvhd_file_mod_timestamp(par_path, err);
|
||||
if (*err != 0) {
|
||||
goto cleanup_format_buff;
|
||||
}
|
||||
|
||||
if (vhdm->sparse.par_timestamp != par_mod_ts) {
|
||||
/* The last-modified timestamp is to fragile to make this a fatal error.
|
||||
Instead, we inform the caller of the potential problem. */
|
||||
@@ -438,57 +585,78 @@ MVHDMeta* mvhd_open(const char* path, bool readonly, int* err) {
|
||||
if (vhdm->parent == NULL) {
|
||||
goto cleanup_format_buff;
|
||||
}
|
||||
|
||||
if (memcmp(vhdm->sparse.par_uuid, vhdm->parent->footer.uuid, sizeof vhdm->sparse.par_uuid) != 0) {
|
||||
*err = MVHD_ERR_INVALID_PAR_UUID;
|
||||
goto cleanup_format_buff;
|
||||
}
|
||||
}
|
||||
/* If we've reached this point, we are good to go, so skip the cleanup steps */
|
||||
|
||||
/*
|
||||
* If we've reached this point, we are good to go,
|
||||
* so skip the cleanup steps.
|
||||
*/
|
||||
goto end;
|
||||
|
||||
cleanup_format_buff:
|
||||
free(vhdm->format_buffer.zero_data);
|
||||
vhdm->format_buffer.zero_data = NULL;
|
||||
|
||||
cleanup_bitmap:
|
||||
free(vhdm->bitmap.curr_bitmap);
|
||||
vhdm->bitmap.curr_bitmap = NULL;
|
||||
|
||||
cleanup_bat:
|
||||
free(vhdm->block_offset);
|
||||
vhdm->block_offset = NULL;
|
||||
|
||||
cleanup_file:
|
||||
fclose(vhdm->f);
|
||||
vhdm->f = NULL;
|
||||
|
||||
cleanup_vhdm:
|
||||
free(vhdm);
|
||||
vhdm = NULL;
|
||||
|
||||
end:
|
||||
return vhdm;
|
||||
}
|
||||
|
||||
void mvhd_close(MVHDMeta* vhdm) {
|
||||
if (vhdm != NULL) {
|
||||
if (vhdm->parent != NULL) {
|
||||
mvhd_close(vhdm->parent);
|
||||
}
|
||||
fclose(vhdm->f);
|
||||
if (vhdm->block_offset != NULL) {
|
||||
free(vhdm->block_offset);
|
||||
vhdm->block_offset = NULL;
|
||||
}
|
||||
if (vhdm->bitmap.curr_bitmap != NULL) {
|
||||
free(vhdm->bitmap.curr_bitmap);
|
||||
vhdm->bitmap.curr_bitmap = NULL;
|
||||
}
|
||||
if (vhdm->format_buffer.zero_data != NULL) {
|
||||
free(vhdm->format_buffer.zero_data);
|
||||
vhdm->format_buffer.zero_data = NULL;
|
||||
}
|
||||
free(vhdm);
|
||||
vhdm = NULL;
|
||||
|
||||
MVHDAPI void
|
||||
mvhd_close(MVHDMeta* vhdm)
|
||||
{
|
||||
if (vhdm == NULL)
|
||||
return;
|
||||
|
||||
if (vhdm->parent != NULL) {
|
||||
mvhd_close(vhdm->parent);
|
||||
}
|
||||
|
||||
fclose(vhdm->f);
|
||||
|
||||
if (vhdm->block_offset != NULL) {
|
||||
free(vhdm->block_offset);
|
||||
vhdm->block_offset = NULL;
|
||||
}
|
||||
if (vhdm->bitmap.curr_bitmap != NULL) {
|
||||
free(vhdm->bitmap.curr_bitmap);
|
||||
vhdm->bitmap.curr_bitmap = NULL;
|
||||
}
|
||||
if (vhdm->format_buffer.zero_data != NULL) {
|
||||
free(vhdm->format_buffer.zero_data);
|
||||
vhdm->format_buffer.zero_data = NULL;
|
||||
}
|
||||
|
||||
free(vhdm);
|
||||
}
|
||||
|
||||
int mvhd_diff_update_par_timestamp(MVHDMeta* vhdm, int* err) {
|
||||
|
||||
MVHDAPI int
|
||||
mvhd_diff_update_par_timestamp(MVHDMeta* vhdm, int* err)
|
||||
{
|
||||
uint8_t sparse_buff[1024];
|
||||
|
||||
if (vhdm == NULL || err == NULL) {
|
||||
*err = MVHD_ERR_INVALID_PARAMS;
|
||||
return -1;
|
||||
@@ -497,7 +665,7 @@ int mvhd_diff_update_par_timestamp(MVHDMeta* vhdm, int* err) {
|
||||
*err = MVHD_ERR_TYPE;
|
||||
return -1;
|
||||
}
|
||||
char* par_path = mvhd_get_diff_parent_path(vhdm, err);
|
||||
char* par_path = get_diff_parent_path(vhdm, err);
|
||||
if (par_path == NULL) {
|
||||
return -1;
|
||||
}
|
||||
@@ -505,31 +673,53 @@ int mvhd_diff_update_par_timestamp(MVHDMeta* vhdm, int* err) {
|
||||
if (*err != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Update the timestamp and sparse header checksum */
|
||||
vhdm->sparse.par_timestamp = par_mod_ts;
|
||||
vhdm->sparse.checksum = mvhd_gen_sparse_checksum(&vhdm->sparse);
|
||||
|
||||
/* Generate and write the updated sparse header */
|
||||
mvhd_header_to_buffer(&vhdm->sparse, sparse_buff);
|
||||
mvhd_fseeko64(vhdm->f, (int64_t)vhdm->footer.data_offset, SEEK_SET);
|
||||
fwrite(sparse_buff, sizeof sparse_buff, 1, vhdm->f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mvhd_read_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) {
|
||||
|
||||
MVHDAPI int
|
||||
mvhd_read_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff)
|
||||
{
|
||||
return vhdm->read_sectors(vhdm, offset, num_sectors, out_buff);
|
||||
}
|
||||
|
||||
int mvhd_write_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) {
|
||||
|
||||
MVHDAPI int
|
||||
mvhd_write_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff)
|
||||
{
|
||||
return vhdm->write_sectors(vhdm, offset, num_sectors, in_buff);
|
||||
}
|
||||
|
||||
int mvhd_format_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors) {
|
||||
|
||||
MVHDAPI int
|
||||
mvhd_format_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors)
|
||||
{
|
||||
int num_full = num_sectors / vhdm->format_buffer.sector_count;
|
||||
int remain = num_sectors % vhdm->format_buffer.sector_count;
|
||||
|
||||
for (int i = 0; i < num_full; i++) {
|
||||
vhdm->write_sectors(vhdm, offset, vhdm->format_buffer.sector_count, vhdm->format_buffer.zero_data);
|
||||
offset += vhdm->format_buffer.sector_count;
|
||||
}
|
||||
|
||||
vhdm->write_sectors(vhdm, offset, remain, vhdm->format_buffer.zero_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
MVHDAPI MVHDType
|
||||
mvhd_get_type(MVHDMeta* vhdm)
|
||||
{
|
||||
return vhdm->footer.disk_type;
|
||||
}
|
||||
@@ -1,11 +1,49 @@
|
||||
/*
|
||||
* MiniVHD Minimalist VHD implementation in C.
|
||||
* MiniVHD is a minimalist implementation of read/write/creation
|
||||
* of VHD files. It is designed to read and write to VHD files
|
||||
* at a sector level. It does not enable file access, or provide
|
||||
* mounting options. Those features are left to more advanced
|
||||
* libraries and/or the operating system.
|
||||
*
|
||||
* This file is part of the MiniVHD Project.
|
||||
*
|
||||
* Definitions for the MiniVHD library.
|
||||
*
|
||||
* Version: @(#)minivhd.h 1.0.3 2021/04/16
|
||||
*
|
||||
* Authors: Sherman Perry, <shermperry@gmail.com>
|
||||
* Fred N. van Kempen, <waltje@varcem.com>
|
||||
*
|
||||
* Copyright 2019-2021 Sherman Perry.
|
||||
* Copyright 2021 Fred N. van Kempen.
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documenta-
|
||||
* tion files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall
|
||||
* be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF O R IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MINIVHD_H
|
||||
#define MINIVHD_H
|
||||
# define MINIVHD_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern int mvhd_errno;
|
||||
|
||||
typedef enum MVHDError {
|
||||
MVHD_ERR_MEM = -128,
|
||||
@@ -46,6 +84,11 @@ typedef struct MVHDGeom {
|
||||
uint8_t spt;
|
||||
} MVHDGeom;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*mvhd_progress_callback)(uint32_t current_sector, uint32_t total_sectors);
|
||||
|
||||
typedef struct MVHDCreationOptions {
|
||||
@@ -60,6 +103,42 @@ typedef struct MVHDCreationOptions {
|
||||
|
||||
typedef struct MVHDMeta MVHDMeta;
|
||||
|
||||
|
||||
extern int mvhd_errno;
|
||||
|
||||
|
||||
/* Shared-library madness. */
|
||||
//#if defined(_WIN32)
|
||||
//# ifdef STATIC
|
||||
# define MVHDAPI /*nothing*/
|
||||
//# else
|
||||
//# ifdef BUILDING_LIBRARY
|
||||
//# define MVHDAPI __declspec(dllexport)
|
||||
//# else
|
||||
//# define MVHDAPI __declspec(dllimport)
|
||||
//# endif
|
||||
//# endif
|
||||
//#elif defined(__GNUC__)
|
||||
//# ifdef BUILDING_LIBRARY
|
||||
//# define MVHDAPI __attribute__((visibility("default")))
|
||||
//# else
|
||||
//# define MVHDAPI /*nothing*/
|
||||
//# endif
|
||||
//#else
|
||||
//# define MVHDAPI /*nothing*/
|
||||
//#endif
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return the library version as a string
|
||||
*/
|
||||
MVHDAPI const char *mvhd_version(void);
|
||||
|
||||
/**
|
||||
* \brief Return the library version as a number
|
||||
*/
|
||||
MVHDAPI uint32_t mvhd_version_id(void);
|
||||
|
||||
/**
|
||||
* \brief Output a string from a MiniVHD error number
|
||||
*
|
||||
@@ -67,17 +146,26 @@ typedef struct MVHDMeta MVHDMeta;
|
||||
*
|
||||
* \return Error string
|
||||
*/
|
||||
const char* mvhd_strerr(MVHDError err);
|
||||
MVHDAPI const char* mvhd_strerr(MVHDError err);
|
||||
|
||||
/**
|
||||
* \brief A simple test to see if a given file is a VHD
|
||||
*
|
||||
* \param [in] f file to test
|
||||
*
|
||||
* \retval true if f is a VHD
|
||||
* \retval false if f is not a VHD
|
||||
* \retval 1 if f is a VHD
|
||||
* \retval 0 if f is not a VHD
|
||||
*/
|
||||
bool mvhd_file_is_vhd(FILE* f);
|
||||
MVHDAPI int mvhd_file_is_vhd(FILE* f);
|
||||
|
||||
/**
|
||||
* \brief Return the file type of the given file
|
||||
*
|
||||
* \param [in] vhdm VHD to check.
|
||||
*
|
||||
* \retval one of the defined MVHDType values
|
||||
*/
|
||||
MVHDAPI MVHDType mvhd_get_type(MVHDMeta* vhdm);
|
||||
|
||||
/**
|
||||
* \brief Open a VHD image for reading and/or writing
|
||||
@@ -89,7 +177,7 @@ bool mvhd_file_is_vhd(FILE* f);
|
||||
*
|
||||
* \param [in] Absolute path to VHD file. Relative path will cause issues when opening
|
||||
* a differencing VHD file
|
||||
* \param [in] readonly set this to true to open the VHD in a read only manner
|
||||
* \param [in] readonly set this to 1 to open the VHD in a read only manner
|
||||
* \param [out] err will be set if the VHD fails to open. Value could be one of
|
||||
* MVHD_ERR_MEM, MVHD_ERR_FILE, MVHD_ERR_NOT_VHD, MVHD_ERR_FOOTER_CHECKSUM, MVHD_ERR_SPARSE_CHECKSUM,
|
||||
* MVHD_ERR_TYPE, MVHD_ERR_TIMESTAMP
|
||||
@@ -98,7 +186,7 @@ bool mvhd_file_is_vhd(FILE* f);
|
||||
* \return MVHDMeta pointer. If NULL, check err. err may also be set to MVHD_ERR_TIMESTAMP if
|
||||
* opening a differencing VHD.
|
||||
*/
|
||||
MVHDMeta* mvhd_open(const char* path, bool readonly, int* err);
|
||||
MVHDAPI MVHDMeta* mvhd_open(const char* path, int readonly, int* err);
|
||||
|
||||
/**
|
||||
* \brief Update the parent modified timestamp in the VHD file
|
||||
@@ -116,7 +204,7 @@ MVHDMeta* mvhd_open(const char* path, bool readonly, int* err);
|
||||
*
|
||||
* \return non-zero on error, 0 on success
|
||||
*/
|
||||
int mvhd_diff_update_par_timestamp(MVHDMeta* vhdm, int* err);
|
||||
MVHDAPI int mvhd_diff_update_par_timestamp(MVHDMeta* vhdm, int* err);
|
||||
|
||||
/**
|
||||
* \brief Create a fixed VHD image
|
||||
@@ -128,7 +216,7 @@ int mvhd_diff_update_par_timestamp(MVHDMeta* vhdm, int* err);
|
||||
*
|
||||
* \retval NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct
|
||||
*/
|
||||
MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* err, mvhd_progress_callback progress_callback);
|
||||
MVHDAPI MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* err, mvhd_progress_callback progress_callback);
|
||||
|
||||
/**
|
||||
* \brief Create sparse (dynamic) VHD image.
|
||||
@@ -139,7 +227,7 @@ MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* err, mvhd_prog
|
||||
*
|
||||
* \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct
|
||||
*/
|
||||
MVHDMeta* mvhd_create_sparse(const char* path, MVHDGeom geom, int* err);
|
||||
MVHDAPI MVHDMeta* mvhd_create_sparse(const char* path, MVHDGeom geom, int* err);
|
||||
|
||||
/**
|
||||
* \brief Create differencing VHD imagee.
|
||||
@@ -150,7 +238,7 @@ MVHDMeta* mvhd_create_sparse(const char* path, MVHDGeom geom, int* err);
|
||||
*
|
||||
* \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct
|
||||
*/
|
||||
MVHDMeta* mvhd_create_diff(const char* path, const char* par_path, int* err);
|
||||
MVHDAPI MVHDMeta* mvhd_create_diff(const char* path, const char* par_path, int* err);
|
||||
|
||||
/**
|
||||
* \brief Create a VHD using the provided options
|
||||
@@ -162,14 +250,14 @@ MVHDMeta* mvhd_create_diff(const char* path, const char* par_path, int* err);
|
||||
*
|
||||
* \retval NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct
|
||||
*/
|
||||
MVHDMeta* mvhd_create_ex(MVHDCreationOptions options, int* err);
|
||||
MVHDAPI MVHDMeta* mvhd_create_ex(MVHDCreationOptions options, int* err);
|
||||
|
||||
/**
|
||||
* \brief Safely close a VHD image
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure to close
|
||||
*/
|
||||
void mvhd_close(MVHDMeta* vhdm);
|
||||
MVHDAPI void mvhd_close(MVHDMeta* vhdm);
|
||||
|
||||
/**
|
||||
* \brief Calculate hard disk geometry from a provided size
|
||||
@@ -189,7 +277,47 @@ void mvhd_close(MVHDMeta* vhdm);
|
||||
*
|
||||
* \return MVHDGeom the calculated geometry. This can be used in the appropriate create functions.
|
||||
*/
|
||||
MVHDGeom mvhd_calculate_geometry(uint64_t size);
|
||||
MVHDAPI MVHDGeom mvhd_calculate_geometry(uint64_t size);
|
||||
|
||||
/**
|
||||
* \brief Get the CHS geometry from the image
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*
|
||||
* \return The CHS geometry as stored in the image
|
||||
*/
|
||||
MVHDAPI MVHDGeom mvhd_get_geometry(MVHDMeta* vhdm);
|
||||
|
||||
/**
|
||||
* \brief Get the 'current_size' value from the image
|
||||
*
|
||||
* Note that the size returned may not match the size calculated from the
|
||||
* CHS geometry. It is up to the caller to decide how best to handle this.
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*
|
||||
* \return The 'current_size' value in bytes, as stored in the image.
|
||||
* Note, this may not match the CHS geometry.
|
||||
*/
|
||||
MVHDAPI uint64_t mvhd_get_current_size(MVHDMeta* vhdm);
|
||||
|
||||
/**
|
||||
* \brief Calculate CHS geometry size in bytes
|
||||
*
|
||||
* \param [in] geom the CHS geometry to calculate
|
||||
*
|
||||
* \return the size in bytes
|
||||
*/
|
||||
MVHDAPI uint64_t mvhd_calc_size_bytes(MVHDGeom *geom);
|
||||
|
||||
/**
|
||||
* \brief Calculate CHS geometry size in sectors
|
||||
*
|
||||
* \param [in] geom the CHS geometry to calculate
|
||||
*
|
||||
* \return the size in sectors
|
||||
*/
|
||||
MVHDAPI uint32_t mvhd_calc_size_sectors(MVHDGeom *geom);
|
||||
|
||||
/**
|
||||
* \brief Convert a raw disk image to a fixed VHD image
|
||||
@@ -200,7 +328,7 @@ MVHDGeom mvhd_calculate_geometry(uint64_t size);
|
||||
*
|
||||
* \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct
|
||||
*/
|
||||
MVHDMeta* mvhd_convert_to_vhd_fixed(const char* utf8_raw_path, const char* utf8_vhd_path, int* err);
|
||||
MVHDAPI MVHDMeta* mvhd_convert_to_vhd_fixed(const char* utf8_raw_path, const char* utf8_vhd_path, int* err);
|
||||
|
||||
/**
|
||||
* \brief Convert a raw disk image to a sparse VHD image
|
||||
@@ -211,7 +339,7 @@ MVHDMeta* mvhd_convert_to_vhd_fixed(const char* utf8_raw_path, const char* utf8_
|
||||
*
|
||||
* \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct
|
||||
*/
|
||||
MVHDMeta* mvhd_convert_to_vhd_sparse(const char* utf8_raw_path, const char* utf8_vhd_path, int* err);
|
||||
MVHDAPI MVHDMeta* mvhd_convert_to_vhd_sparse(const char* utf8_raw_path, const char* utf8_vhd_path, int* err);
|
||||
|
||||
/**
|
||||
* \brief Convert a VHD image to a raw disk image
|
||||
@@ -222,7 +350,7 @@ MVHDMeta* mvhd_convert_to_vhd_sparse(const char* utf8_raw_path, const char* utf8
|
||||
*
|
||||
* \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns the raw disk image FILE pointer
|
||||
*/
|
||||
FILE* mvhd_convert_to_raw(const char* utf8_vhd_path, const char* utf8_raw_path, int *err);
|
||||
MVHDAPI FILE* mvhd_convert_to_raw(const char* utf8_vhd_path, const char* utf8_raw_path, int *err);
|
||||
|
||||
/**
|
||||
* \brief Read sectors from VHD file
|
||||
@@ -236,7 +364,7 @@ FILE* mvhd_convert_to_raw(const char* utf8_vhd_path, const char* utf8_raw_path,
|
||||
*
|
||||
* \return the number of sectors that were not read, or zero
|
||||
*/
|
||||
int mvhd_read_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff);
|
||||
MVHDAPI int mvhd_read_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff);
|
||||
|
||||
/**
|
||||
* \brief Write sectors to VHD file
|
||||
@@ -250,7 +378,7 @@ int mvhd_read_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* ou
|
||||
*
|
||||
* \return the number of sectors that were not written, or zero
|
||||
*/
|
||||
int mvhd_write_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff);
|
||||
MVHDAPI int mvhd_write_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff);
|
||||
|
||||
/**
|
||||
* \brief Write zeroed sectors to VHD file
|
||||
@@ -265,5 +393,11 @@ int mvhd_write_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* i
|
||||
*
|
||||
* \return the number of sectors that were not written, or zero
|
||||
*/
|
||||
int mvhd_format_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors);
|
||||
MVHDAPI int mvhd_format_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*MINIVHD_H*/
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef MINIVHD_CREATE_H
|
||||
#define MINIVHD_CREATE_H
|
||||
#include <stdio.h>
|
||||
#include "minivhd.h"
|
||||
|
||||
MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, uint64_t size_in_bytes, MVHDGeom* geom, int* err, mvhd_progress_callback progress_callback);
|
||||
|
||||
#endif
|
||||
@@ -1,96 +0,0 @@
|
||||
#ifndef MINIVHD_INTERNAL_H
|
||||
#define MINIVHD_INTERNAL_H
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define MVHD_FOOTER_SIZE 512
|
||||
#define MVHD_SPARSE_SIZE 1024
|
||||
|
||||
#define MVHD_SECTOR_SIZE 512
|
||||
#define MVHD_BAT_ENT_PER_SECT 128
|
||||
|
||||
#define MVHD_MAX_SIZE_IN_BYTES 0x1fe00000000
|
||||
|
||||
#define MVHD_SPARSE_BLK 0xffffffff
|
||||
/* For simplicity, we don't handle paths longer than this
|
||||
* Note, this is the max path in characters, as that is what
|
||||
* Windows uses
|
||||
*/
|
||||
#define MVHD_MAX_PATH_CHARS 260
|
||||
#define MVHD_MAX_PATH_BYTES 1040
|
||||
|
||||
#define MVHD_DIF_LOC_W2RU 0x57327275
|
||||
#define MVHD_DIF_LOC_W2KU 0x57326B75
|
||||
|
||||
typedef struct MVHDSectorBitmap {
|
||||
uint8_t* curr_bitmap;
|
||||
int sector_count;
|
||||
int curr_block;
|
||||
} MVHDSectorBitmap;
|
||||
|
||||
typedef struct MVHDFooter {
|
||||
uint8_t cookie[8];
|
||||
uint32_t features;
|
||||
uint32_t fi_fmt_vers;
|
||||
uint64_t data_offset;
|
||||
uint32_t timestamp;
|
||||
uint8_t cr_app[4];
|
||||
uint32_t cr_vers;
|
||||
uint8_t cr_host_os[4];
|
||||
uint64_t orig_sz;
|
||||
uint64_t curr_sz;
|
||||
struct {
|
||||
uint16_t cyl;
|
||||
uint8_t heads;
|
||||
uint8_t spt;
|
||||
} geom;
|
||||
uint32_t disk_type;
|
||||
uint32_t checksum;
|
||||
uint8_t uuid[16];
|
||||
uint8_t saved_st;
|
||||
uint8_t reserved[427];
|
||||
} MVHDFooter;
|
||||
|
||||
typedef struct MVHDSparseHeader {
|
||||
uint8_t cookie[8];
|
||||
uint64_t data_offset;
|
||||
uint64_t bat_offset;
|
||||
uint32_t head_vers;
|
||||
uint32_t max_bat_ent;
|
||||
uint32_t block_sz;
|
||||
uint32_t checksum;
|
||||
uint8_t par_uuid[16];
|
||||
uint32_t par_timestamp;
|
||||
uint32_t reserved_1;
|
||||
uint8_t par_utf16_name[512];
|
||||
struct {
|
||||
uint32_t plat_code;
|
||||
uint32_t plat_data_space;
|
||||
uint32_t plat_data_len;
|
||||
uint32_t reserved;
|
||||
uint64_t plat_data_offset;
|
||||
} par_loc_entry[8];
|
||||
uint8_t reserved_2[256];
|
||||
} MVHDSparseHeader;
|
||||
|
||||
typedef struct MVHDMeta MVHDMeta;
|
||||
struct MVHDMeta {
|
||||
FILE* f;
|
||||
bool readonly;
|
||||
char filename[MVHD_MAX_PATH_BYTES];
|
||||
struct MVHDMeta* parent;
|
||||
MVHDFooter footer;
|
||||
MVHDSparseHeader sparse;
|
||||
uint32_t* block_offset;
|
||||
int sect_per_block;
|
||||
MVHDSectorBitmap bitmap;
|
||||
int (*read_sectors)(MVHDMeta*, uint32_t, int, void*);
|
||||
int (*write_sectors)(MVHDMeta*, uint32_t, int, void*);
|
||||
struct {
|
||||
uint8_t* zero_data;
|
||||
int sector_count;
|
||||
} format_buffer;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,28 +1,61 @@
|
||||
/**
|
||||
* \file
|
||||
* \brief Sector reading and writing implementations
|
||||
/*
|
||||
* MiniVHD Minimalist VHD implementation in C.
|
||||
*
|
||||
* This file is part of the MiniVHD Project.
|
||||
*
|
||||
* Sector reading and writing implementations.
|
||||
*
|
||||
* Version: @(#)io.c 1.0.3 2021/04/16
|
||||
*
|
||||
* Author: Sherman Perry, <shermperry@gmail.com>
|
||||
*
|
||||
* Copyright 2019-2021 Sherman Perry.
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documenta-
|
||||
* tion files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall
|
||||
* be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF O R IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "minivhd_internal.h"
|
||||
#include "minivhd_util.h"
|
||||
#include <time.h>
|
||||
#include "minivhd.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* The following bit array macros adapted from
|
||||
http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html */
|
||||
|
||||
#define VHD_SETBIT(A,k) ( A[(k/8)] |= (0x80 >> (k%8)) )
|
||||
#define VHD_CLEARBIT(A,k) ( A[(k/8)] &= ~(0x80 >> (k%8)) )
|
||||
#define VHD_TESTBIT(A,k) ( A[(k/8)] & (0x80 >> (k%8)) )
|
||||
/*
|
||||
* The following bit array macros adapted from:
|
||||
*
|
||||
* http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html
|
||||
*/
|
||||
#define VHD_SETBIT(A,k) ( A[(k>>3)] |= (0x80 >> (k&7)) )
|
||||
#define VHD_CLEARBIT(A,k) ( A[(k>>3)] &= ~(0x80 >> (k&7)) )
|
||||
#define VHD_TESTBIT(A,k) ( A[(k>>3)] & (0x80 >> (k&7)) )
|
||||
|
||||
static inline void mvhd_check_sectors(uint32_t offset, int num_sectors, uint32_t total_sectors, int* transfer_sect, int* trunc_sect);
|
||||
static void mvhd_read_sect_bitmap(MVHDMeta* vhdm, int blk);
|
||||
static void mvhd_write_bat_entry(MVHDMeta* vhdm, int blk);
|
||||
static void mvhd_create_block(MVHDMeta* vhdm, int blk);
|
||||
static void mvhd_write_curr_sect_bitmap(MVHDMeta* vhdm);
|
||||
|
||||
/**
|
||||
* \brief Check that we will not be overflowing buffers
|
||||
@@ -34,22 +67,30 @@ static void mvhd_write_curr_sect_bitmap(MVHDMeta* vhdm);
|
||||
* This may be lower than num_sectors if offset + num_sectors >= total_sectors
|
||||
* \param [out] trunc_sectors The number of sectors truncated if transfer_sectors < num_sectors
|
||||
*/
|
||||
static inline void mvhd_check_sectors(uint32_t offset, int num_sectors, uint32_t total_sectors, int* transfer_sect, int* trunc_sect) {
|
||||
static inline void
|
||||
check_sectors(uint32_t offset, int num_sectors, uint32_t total_sectors, int* transfer_sect, int* trunc_sect)
|
||||
{
|
||||
*transfer_sect = num_sectors;
|
||||
*trunc_sect = 0;
|
||||
|
||||
if ((total_sectors - offset) < (uint32_t)*transfer_sect) {
|
||||
*transfer_sect = total_sectors - offset;
|
||||
*trunc_sect = num_sectors - *transfer_sect;
|
||||
}
|
||||
}
|
||||
|
||||
void mvhd_write_empty_sectors(FILE* f, int sector_count) {
|
||||
|
||||
void
|
||||
mvhd_write_empty_sectors(FILE* f, int sector_count)
|
||||
{
|
||||
uint8_t zero_bytes[MVHD_SECTOR_SIZE] = {0};
|
||||
|
||||
for (int i = 0; i < sector_count; i++) {
|
||||
fwrite(zero_bytes, sizeof zero_bytes, 1, f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Read the sector bitmap for a block.
|
||||
*
|
||||
@@ -59,22 +100,28 @@ void mvhd_write_empty_sectors(FILE* f, int sector_count) {
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] blk The block for which to read the sector bitmap from
|
||||
*/
|
||||
static void mvhd_read_sect_bitmap(MVHDMeta* vhdm, int blk) {
|
||||
static void
|
||||
read_sect_bitmap(MVHDMeta* vhdm, int blk)
|
||||
{
|
||||
if (vhdm->block_offset[blk] != MVHD_SPARSE_BLK) {
|
||||
mvhd_fseeko64(vhdm->f, (uint64_t)vhdm->block_offset[blk] * MVHD_SECTOR_SIZE, SEEK_SET);
|
||||
(void) !fread(vhdm->bitmap.curr_bitmap, vhdm->bitmap.sector_count * MVHD_SECTOR_SIZE, 1, vhdm->f);
|
||||
} else {
|
||||
memset(vhdm->bitmap.curr_bitmap, 0, vhdm->bitmap.sector_count * MVHD_SECTOR_SIZE);
|
||||
}
|
||||
|
||||
vhdm->bitmap.curr_block = blk;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Write the current sector bitmap in memory to file
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
static void mvhd_write_curr_sect_bitmap(MVHDMeta* vhdm) {
|
||||
static void
|
||||
write_curr_sect_bitmap(MVHDMeta* vhdm)
|
||||
{
|
||||
if (vhdm->bitmap.curr_block >= 0) {
|
||||
int64_t abs_offset = (int64_t)vhdm->block_offset[vhdm->bitmap.curr_block] * MVHD_SECTOR_SIZE;
|
||||
mvhd_fseeko64(vhdm->f, abs_offset, SEEK_SET);
|
||||
@@ -82,19 +129,24 @@ static void mvhd_write_curr_sect_bitmap(MVHDMeta* vhdm) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Write block offset from memory into file
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] blk The block for which to write the offset for
|
||||
*/
|
||||
static void mvhd_write_bat_entry(MVHDMeta* vhdm, int blk) {
|
||||
static void
|
||||
write_bat_entry(MVHDMeta* vhdm, int blk)
|
||||
{
|
||||
uint64_t table_offset = vhdm->sparse.bat_offset + ((uint64_t)blk * sizeof *vhdm->block_offset);
|
||||
uint32_t offset = mvhd_to_be32(vhdm->block_offset[blk]);
|
||||
|
||||
mvhd_fseeko64(vhdm->f, table_offset, SEEK_SET);
|
||||
fwrite(&offset, sizeof offset, 1, vhdm->f);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Create an empty block in a sparse or differencing VHD image
|
||||
*
|
||||
@@ -109,18 +161,23 @@ static void mvhd_write_bat_entry(MVHDMeta* vhdm, int blk) {
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] blk The block number to create
|
||||
*/
|
||||
static void mvhd_create_block(MVHDMeta* vhdm, int blk) {
|
||||
static void
|
||||
create_block(MVHDMeta* vhdm, int blk)
|
||||
{
|
||||
uint8_t footer[MVHD_FOOTER_SIZE];
|
||||
|
||||
/* Seek to where the footer SHOULD be */
|
||||
mvhd_fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END);
|
||||
(void) !fread(footer, sizeof footer, 1, vhdm->f);
|
||||
mvhd_fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END);
|
||||
|
||||
if (!mvhd_is_conectix_str(footer)) {
|
||||
/* Oh dear. We use the header instead, since something has gone wrong at the footer */
|
||||
mvhd_fseeko64(vhdm->f, 0, SEEK_SET);
|
||||
(void) !fread(footer, sizeof footer, 1, vhdm->f);
|
||||
mvhd_fseeko64(vhdm->f, 0, SEEK_END);
|
||||
}
|
||||
|
||||
int64_t abs_offset = mvhd_ftello64(vhdm->f);
|
||||
if (abs_offset % MVHD_SECTOR_SIZE != 0) {
|
||||
/* Yikes! We're supposed to be on a sector boundary. Add some padding */
|
||||
@@ -131,52 +188,68 @@ static void mvhd_create_block(MVHDMeta* vhdm, int blk) {
|
||||
}
|
||||
abs_offset += padding_amount;
|
||||
}
|
||||
|
||||
uint32_t sect_offset = (uint32_t)(abs_offset / MVHD_SECTOR_SIZE);
|
||||
int blk_size_sectors = vhdm->sparse.block_sz / MVHD_SECTOR_SIZE;
|
||||
mvhd_write_empty_sectors(vhdm->f, vhdm->bitmap.sector_count + blk_size_sectors);
|
||||
|
||||
/* Add a bit of padding. That's what Windows appears to do, although it's not strictly necessary... */
|
||||
mvhd_write_empty_sectors(vhdm->f, 5);
|
||||
|
||||
/* And we finish with the footer */
|
||||
fwrite(footer, sizeof footer, 1, vhdm->f);
|
||||
|
||||
/* We no longer have a sparse block. Update that BAT! */
|
||||
vhdm->block_offset[blk] = sect_offset;
|
||||
mvhd_write_bat_entry(vhdm, blk);
|
||||
write_bat_entry(vhdm, blk);
|
||||
}
|
||||
|
||||
int mvhd_fixed_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) {
|
||||
|
||||
int
|
||||
mvhd_fixed_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) {
|
||||
int64_t addr;
|
||||
int transfer_sectors, truncated_sectors;
|
||||
uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE);
|
||||
mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors);
|
||||
|
||||
check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors);
|
||||
|
||||
addr = (int64_t)offset * MVHD_SECTOR_SIZE;
|
||||
mvhd_fseeko64(vhdm->f, addr, SEEK_SET);
|
||||
(void) !fread(out_buff, transfer_sectors*MVHD_SECTOR_SIZE, 1, vhdm->f);
|
||||
|
||||
return truncated_sectors;
|
||||
}
|
||||
|
||||
int mvhd_sparse_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) {
|
||||
|
||||
int
|
||||
mvhd_sparse_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff)
|
||||
{
|
||||
int transfer_sectors, truncated_sectors;
|
||||
uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE);
|
||||
mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors);
|
||||
|
||||
check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors);
|
||||
|
||||
uint8_t* buff = (uint8_t*)out_buff;
|
||||
int64_t addr;
|
||||
uint32_t s, ls;
|
||||
int blk, prev_blk, sib;
|
||||
ls = offset + transfer_sectors;
|
||||
prev_blk = -1;
|
||||
|
||||
for (s = offset; s < ls; s++) {
|
||||
blk = s / vhdm->sect_per_block;
|
||||
sib = s % vhdm->sect_per_block;
|
||||
if (blk != prev_blk) {
|
||||
prev_blk = blk;
|
||||
if (vhdm->bitmap.curr_block != blk) {
|
||||
mvhd_read_sect_bitmap(vhdm, blk);
|
||||
read_sect_bitmap(vhdm, blk);
|
||||
mvhd_fseeko64(vhdm->f, (uint64_t)sib * MVHD_SECTOR_SIZE, SEEK_CUR);
|
||||
} else {
|
||||
addr = ((int64_t)vhdm->block_offset[blk] + vhdm->bitmap.sector_count + sib) * MVHD_SECTOR_SIZE;
|
||||
mvhd_fseeko64(vhdm->f, addr, SEEK_SET);
|
||||
}
|
||||
}
|
||||
|
||||
if (VHD_TESTBIT(vhdm->bitmap.curr_bitmap, sib)) {
|
||||
(void) !fread(buff, MVHD_SECTOR_SIZE, 1, vhdm->f);
|
||||
} else {
|
||||
@@ -185,29 +258,37 @@ int mvhd_sparse_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out
|
||||
}
|
||||
buff += MVHD_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
return truncated_sectors;
|
||||
}
|
||||
|
||||
int mvhd_diff_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) {
|
||||
|
||||
int
|
||||
mvhd_diff_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff)
|
||||
{
|
||||
int transfer_sectors, truncated_sectors;
|
||||
uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE);
|
||||
mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors);
|
||||
|
||||
check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors);
|
||||
|
||||
uint8_t* buff = (uint8_t*)out_buff;
|
||||
MVHDMeta* curr_vhdm = vhdm;
|
||||
uint32_t s, ls;
|
||||
int blk, sib;
|
||||
ls = offset + transfer_sectors;
|
||||
|
||||
for (s = offset; s < ls; s++) {
|
||||
while (curr_vhdm->footer.disk_type == MVHD_TYPE_DIFF) {
|
||||
blk = s / curr_vhdm->sect_per_block;
|
||||
sib = s % curr_vhdm->sect_per_block;
|
||||
if (curr_vhdm->bitmap.curr_block != blk) {
|
||||
mvhd_read_sect_bitmap(curr_vhdm, blk);
|
||||
read_sect_bitmap(curr_vhdm, blk);
|
||||
}
|
||||
if (!VHD_TESTBIT(curr_vhdm->bitmap.curr_bitmap, sib)) {
|
||||
curr_vhdm = curr_vhdm->parent;
|
||||
} else { break; }
|
||||
}
|
||||
|
||||
/* We handle actual sector reading using the fixed or sparse functions,
|
||||
as a differencing VHD is also a sparse VHD */
|
||||
if (curr_vhdm->footer.disk_type == MVHD_TYPE_DIFF || curr_vhdm->footer.disk_type == MVHD_TYPE_DYNAMIC) {
|
||||
@@ -215,49 +296,65 @@ int mvhd_diff_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_b
|
||||
} else {
|
||||
mvhd_fixed_read(curr_vhdm, s, 1, buff);
|
||||
}
|
||||
|
||||
curr_vhdm = vhdm;
|
||||
buff += MVHD_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
return truncated_sectors;
|
||||
}
|
||||
|
||||
int mvhd_fixed_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) {
|
||||
|
||||
int
|
||||
mvhd_fixed_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff)
|
||||
{
|
||||
int64_t addr;
|
||||
int transfer_sectors, truncated_sectors;
|
||||
uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE);
|
||||
mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors);
|
||||
|
||||
check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors);
|
||||
|
||||
addr = (int64_t)offset * MVHD_SECTOR_SIZE;
|
||||
mvhd_fseeko64(vhdm->f, addr, SEEK_SET);
|
||||
fwrite(in_buff, transfer_sectors*MVHD_SECTOR_SIZE, 1, vhdm->f);
|
||||
|
||||
return truncated_sectors;
|
||||
}
|
||||
|
||||
int mvhd_sparse_diff_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) {
|
||||
|
||||
int
|
||||
mvhd_sparse_diff_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff)
|
||||
{
|
||||
int transfer_sectors, truncated_sectors;
|
||||
uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE);
|
||||
mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors);
|
||||
|
||||
check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors);
|
||||
|
||||
uint8_t* buff = (uint8_t*)in_buff;
|
||||
int64_t addr;
|
||||
uint32_t s, ls;
|
||||
int blk, prev_blk, sib;
|
||||
ls = offset + transfer_sectors;
|
||||
prev_blk = -1;
|
||||
|
||||
for (s = offset; s < ls; s++) {
|
||||
blk = s / vhdm->sect_per_block;
|
||||
sib = s % vhdm->sect_per_block;
|
||||
if (vhdm->bitmap.curr_block != blk && prev_blk >= 0) {
|
||||
/* Write the sector bitmap for the previous block, before we replace it. */
|
||||
mvhd_write_curr_sect_bitmap(vhdm);
|
||||
write_curr_sect_bitmap(vhdm);
|
||||
}
|
||||
|
||||
if (vhdm->block_offset[blk] == MVHD_SPARSE_BLK) {
|
||||
/* "read" the sector bitmap first, before creating a new block, as the bitmap will be
|
||||
zero either way */
|
||||
mvhd_read_sect_bitmap(vhdm, blk);
|
||||
mvhd_create_block(vhdm, blk);
|
||||
read_sect_bitmap(vhdm, blk);
|
||||
create_block(vhdm, blk);
|
||||
}
|
||||
|
||||
if (blk != prev_blk) {
|
||||
if (vhdm->bitmap.curr_block != blk) {
|
||||
mvhd_read_sect_bitmap(vhdm, blk);
|
||||
read_sect_bitmap(vhdm, blk);
|
||||
mvhd_fseeko64(vhdm->f, (uint64_t)sib * MVHD_SECTOR_SIZE, SEEK_CUR);
|
||||
} else {
|
||||
addr = ((int64_t)vhdm->block_offset[blk] + vhdm->bitmap.sector_count + sib) * MVHD_SECTOR_SIZE;
|
||||
@@ -265,15 +362,26 @@ int mvhd_sparse_diff_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, voi
|
||||
}
|
||||
prev_blk = blk;
|
||||
}
|
||||
|
||||
fwrite(buff, MVHD_SECTOR_SIZE, 1, vhdm->f);
|
||||
VHD_SETBIT(vhdm->bitmap.curr_bitmap, sib);
|
||||
buff += MVHD_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
/* And write the sector bitmap for the last block we visited to disk */
|
||||
mvhd_write_curr_sect_bitmap(vhdm);
|
||||
write_curr_sect_bitmap(vhdm);
|
||||
|
||||
return truncated_sectors;
|
||||
}
|
||||
|
||||
int mvhd_noop_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) {
|
||||
|
||||
int
|
||||
mvhd_noop_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff)
|
||||
{
|
||||
(void)vhdm;
|
||||
(void)offset;
|
||||
(void)num_sectors;
|
||||
(void)in_buff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
#ifndef MINIVHD_IO_H
|
||||
#define MINIVHD_IO_H
|
||||
#include "minivhd.h"
|
||||
|
||||
/**
|
||||
* \brief Write zero filled sectors to file.
|
||||
*
|
||||
* Note, the caller should set the file position before calling this
|
||||
* function for correct operation.
|
||||
*
|
||||
* \param [in] f File to write sectors to
|
||||
* \param [in] sector_count The number of sectors to write
|
||||
*/
|
||||
void mvhd_write_empty_sectors(FILE* f, int sector_count);
|
||||
|
||||
/**
|
||||
* \brief Read a fixed VHD image
|
||||
*
|
||||
* Fixed VHD images are essentially raw image files with a footer tacked on
|
||||
* the end. They are therefore straightforward to write
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset Sector offset to read from
|
||||
* \param [in] num_sectors The desired number of sectors to read
|
||||
* \param [out] out_buff An output buffer to store read sectors. Must be
|
||||
* large enough to hold num_sectors worth of sectors.
|
||||
*
|
||||
* \retval 0 num_sectors were read from file
|
||||
* \retval >0 < num_sectors were read from file
|
||||
*/
|
||||
int mvhd_fixed_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff);
|
||||
|
||||
/**
|
||||
* \brief Read a sparse VHD image
|
||||
*
|
||||
* Sparse, or dynamic images are VHD images that grow as data is written to them.
|
||||
*
|
||||
* This function implements the logic to read sectors from the file, taking into
|
||||
* account the fact that blocks may be stored on disk in any order, and that the
|
||||
* read could cross block boundaries.
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset Sector offset to read from
|
||||
* \param [in] num_sectors The desired number of sectors to read
|
||||
* \param [out] out_buff An output buffer to store read sectors. Must be
|
||||
* large enough to hold num_sectors worth of sectors.
|
||||
*
|
||||
* \retval 0 num_sectors were read from file
|
||||
* \retval >0 < num_sectors were read from file
|
||||
*/
|
||||
int mvhd_sparse_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff);
|
||||
|
||||
/**
|
||||
* \brief Read a differencing VHD image
|
||||
*
|
||||
* Differencing images are a variant of a sparse image. They contain the grow-on-demand
|
||||
* properties of sparse images, but also reference a parent image. Data is read from the
|
||||
* child image only if it is newer than the data stored in the parent image.
|
||||
*
|
||||
* This function implements the logic to read sectors from the child, or a parent image.
|
||||
* Differencing images may have a differencing image as a parent, creating a chain of images.
|
||||
* There is no theoretical chain length limit, although I do not consider long chains to be
|
||||
* advisable. Verifying the parent-child relationship is not very robust.
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset Sector offset to read from
|
||||
* \param [in] num_sectors The desired number of sectors to read
|
||||
* \param [out] out_buff An output buffer to store read sectors. Must be
|
||||
* large enough to hold num_sectors worth of sectors.
|
||||
*
|
||||
* \retval 0 num_sectors were read from file
|
||||
* \retval >0 < num_sectors were read from file
|
||||
*/
|
||||
int mvhd_diff_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff);
|
||||
|
||||
/**
|
||||
* \brief Write to a fixed VHD image
|
||||
*
|
||||
* Fixed VHD images are essentially raw image files with a footer tacked on
|
||||
* the end. They are therefore straightforward to write
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset Sector offset to write to
|
||||
* \param [in] num_sectors The desired number of sectors to write
|
||||
* \param [in] in_buff A source buffer to write sectors from. Must be
|
||||
* large enough to hold num_sectors worth of sectors.
|
||||
*
|
||||
* \retval 0 num_sectors were written to file
|
||||
* \retval >0 < num_sectors were written to file
|
||||
*/
|
||||
int mvhd_fixed_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff);
|
||||
|
||||
/**
|
||||
* \brief Write to a sparse or differencing VHD image
|
||||
*
|
||||
* Sparse, or dynamic images are VHD images that grow as data is written to them.
|
||||
*
|
||||
* Differencing images are a variant of a sparse image. They contain the grow-on-demand
|
||||
* properties of sparse images, but also reference a parent image. Data is always written
|
||||
* to the child image. This makes writing to differencing images essentially identical to
|
||||
* writing to sparse images, hence they use the same function.
|
||||
*
|
||||
* This function implements the logic to write sectors to the file, taking into
|
||||
* account the fact that blocks may be stored on disk in any order, and that the
|
||||
* write operation could cross block boundaries.
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset Sector offset to write to
|
||||
* \param [in] num_sectors The desired number of sectors to write
|
||||
* \param [in] in_buff A source buffer to write sectors from. Must be
|
||||
* large enough to hold num_sectors worth of sectors.
|
||||
*
|
||||
* \retval 0 num_sectors were written to file
|
||||
* \retval >0 < num_sectors were written to file
|
||||
*/
|
||||
int mvhd_sparse_diff_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff);
|
||||
|
||||
/**
|
||||
* \brief A no-op function to "write" to read-only VHD images
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset Sector offset to write to
|
||||
* \param [in] num_sectors The desired number of sectors to write
|
||||
* \param [in] in_buff A source buffer to write sectors from. Must be
|
||||
* large enough to hold num_sectors worth of sectors.
|
||||
*
|
||||
* \retval 0 num_sectors were written to file
|
||||
* \retval >0 < num_sectors were written to file
|
||||
*/
|
||||
int mvhd_noop_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff);
|
||||
|
||||
#endif
|
||||
@@ -1,167 +0,0 @@
|
||||
/**
|
||||
* \file
|
||||
* \brief Header and footer serialize/deserialize functions
|
||||
*/
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "minivhd_util.h"
|
||||
#include "minivhd_internal.h"
|
||||
|
||||
/* Read data from footer into the struct members, swapping endian where necessary
|
||||
Note: order matters here! We must read each field in the order the struct is in.
|
||||
Doing this may be less elegant than performing a memcpy to a packed struct, but
|
||||
it avoids potential data alignment issues, and the endian swapping allows us to
|
||||
use the fields directly. */
|
||||
|
||||
static void mvhd_next_buffer_to_struct(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer);
|
||||
static void mvhd_next_struct_to_buffer(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer);
|
||||
|
||||
/**
|
||||
* \brief Get the next field from a buffer and store it in a struct member, converting endian if necessary
|
||||
*
|
||||
* \param [out] struct_memb struct member to save the field to
|
||||
* \param [in] memb_size the size of struct_memb, in bytes
|
||||
* \param [in] req_endian is the field a value that requires endian conversion (eg: uint16, uint32)
|
||||
* \param [in] buffer the buffer from which fields are read from. Will be advanced at the end of the function call
|
||||
*/
|
||||
static void mvhd_next_buffer_to_struct(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer) {
|
||||
memcpy(struct_memb, *buffer, memb_size);
|
||||
if (req_endian) {
|
||||
switch (memb_size) {
|
||||
case 2:
|
||||
*(uint16_t*)(struct_memb) = mvhd_from_be16(*(uint16_t*)(struct_memb));
|
||||
break;
|
||||
case 4:
|
||||
*(uint32_t*)(struct_memb) = mvhd_from_be32(*(uint32_t*)(struct_memb));
|
||||
break;
|
||||
case 8:
|
||||
*(uint64_t*)(struct_memb) = mvhd_from_be64(*(uint64_t*)(struct_memb));
|
||||
break;
|
||||
}
|
||||
}
|
||||
*buffer += memb_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Save a struct member into a buffer, converting endian if necessary
|
||||
*
|
||||
* \param [in] struct_memb struct member read from
|
||||
* \param [in] memb_size the size of struct_memb, in bytes
|
||||
* \param [in] req_endian is the field a value that requires endian conversion (eg: uint16, uint32)
|
||||
* \param [out] buffer the buffer from which struct member is saved to. Will be advanced at the end of the function call
|
||||
*/
|
||||
static void mvhd_next_struct_to_buffer(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer) {
|
||||
uint8_t *buf_ptr = *buffer;
|
||||
memcpy(buf_ptr, struct_memb, memb_size);
|
||||
if (req_endian) {
|
||||
switch (memb_size) {
|
||||
case 2:
|
||||
*((uint16_t*)buf_ptr) = mvhd_to_be16(*(uint16_t*)(struct_memb));
|
||||
break;
|
||||
case 4:
|
||||
*((uint32_t*)buf_ptr) = mvhd_to_be32(*(uint32_t*)(struct_memb));
|
||||
break;
|
||||
case 8:
|
||||
*((uint64_t*)buf_ptr) = mvhd_to_be64(*(uint64_t*)(struct_memb));
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf_ptr += memb_size;
|
||||
*buffer = buf_ptr;
|
||||
}
|
||||
|
||||
void mvhd_buffer_to_footer(MVHDFooter* footer, uint8_t* buffer) {
|
||||
uint8_t* buff_ptr = buffer;
|
||||
mvhd_next_buffer_to_struct(&footer->cookie, sizeof footer->cookie, false, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->features, sizeof footer->features, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->fi_fmt_vers, sizeof footer->fi_fmt_vers, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->data_offset, sizeof footer->data_offset, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->timestamp, sizeof footer->timestamp, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->cr_app, sizeof footer->cr_app, false, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->cr_vers, sizeof footer->cr_vers, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->cr_host_os, sizeof footer->cr_host_os, false, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->orig_sz, sizeof footer->orig_sz, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->curr_sz, sizeof footer->curr_sz, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->geom.cyl, sizeof footer->geom.cyl, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->geom.heads, sizeof footer->geom.heads, false, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->geom.spt, sizeof footer->geom.spt, false, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->disk_type, sizeof footer->disk_type, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->checksum, sizeof footer->checksum, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->uuid, sizeof footer->uuid, false, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->saved_st, sizeof footer->saved_st, false, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->reserved, sizeof footer->reserved, false, &buff_ptr);
|
||||
}
|
||||
|
||||
void mvhd_footer_to_buffer(MVHDFooter* footer, uint8_t* buffer) {
|
||||
uint8_t* buff_ptr = buffer;
|
||||
mvhd_next_struct_to_buffer(&footer->cookie, sizeof footer->cookie, false, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->features, sizeof footer->features, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->fi_fmt_vers, sizeof footer->fi_fmt_vers, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->data_offset, sizeof footer->data_offset, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->timestamp, sizeof footer->timestamp, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->cr_app, sizeof footer->cr_app, false, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->cr_vers, sizeof footer->cr_vers, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->cr_host_os, sizeof footer->cr_host_os, false, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->orig_sz, sizeof footer->orig_sz, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->curr_sz, sizeof footer->curr_sz, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->geom.cyl, sizeof footer->geom.cyl, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->geom.heads, sizeof footer->geom.heads, false, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->geom.spt, sizeof footer->geom.spt, false, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->disk_type, sizeof footer->disk_type, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->checksum, sizeof footer->checksum, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->uuid, sizeof footer->uuid, false, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->saved_st, sizeof footer->saved_st, false, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->reserved, sizeof footer->reserved, false, &buff_ptr);
|
||||
}
|
||||
|
||||
void mvhd_buffer_to_header(MVHDSparseHeader* header, uint8_t* buffer) {
|
||||
uint8_t* buff_ptr = buffer;
|
||||
mvhd_next_buffer_to_struct(&header->cookie, sizeof header->cookie, false, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->data_offset, sizeof header->data_offset, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->bat_offset, sizeof header->bat_offset, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->head_vers, sizeof header->head_vers, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->max_bat_ent, sizeof header->max_bat_ent, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->block_sz, sizeof header->block_sz, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->checksum, sizeof header->checksum, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->par_uuid, sizeof header->par_uuid, false, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->par_timestamp, sizeof header->par_timestamp, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->reserved_1, sizeof header->reserved_1, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->par_utf16_name, sizeof header->par_utf16_name, false, &buff_ptr);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_code, sizeof header->par_loc_entry[i].plat_code, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_data_space, sizeof header->par_loc_entry[i].plat_data_space, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_data_len, sizeof header->par_loc_entry[i].plat_data_len, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->par_loc_entry[i].reserved, sizeof header->par_loc_entry[i].reserved, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_data_offset, sizeof header->par_loc_entry[i].plat_data_offset, true, &buff_ptr);
|
||||
}
|
||||
mvhd_next_buffer_to_struct(&header->reserved_2, sizeof header->reserved_2, false, &buff_ptr);
|
||||
}
|
||||
|
||||
void mvhd_header_to_buffer(MVHDSparseHeader* header, uint8_t* buffer) {
|
||||
uint8_t* buff_ptr = buffer;
|
||||
mvhd_next_struct_to_buffer(&header->cookie, sizeof header->cookie, false, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->data_offset, sizeof header->data_offset, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->bat_offset, sizeof header->bat_offset, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->head_vers, sizeof header->head_vers, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->max_bat_ent, sizeof header->max_bat_ent, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->block_sz, sizeof header->block_sz, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->checksum, sizeof header->checksum, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->par_uuid, sizeof header->par_uuid, false, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->par_timestamp, sizeof header->par_timestamp, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->reserved_1, sizeof header->reserved_1, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->par_utf16_name, sizeof header->par_utf16_name, false, &buff_ptr);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_code, sizeof header->par_loc_entry[i].plat_code, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_data_space, sizeof header->par_loc_entry[i].plat_data_space, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_data_len, sizeof header->par_loc_entry[i].plat_data_len, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->par_loc_entry[i].reserved, sizeof header->par_loc_entry[i].reserved, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_data_offset, sizeof header->par_loc_entry[i].plat_data_offset, true, &buff_ptr);
|
||||
}
|
||||
mvhd_next_struct_to_buffer(&header->reserved_2, sizeof header->reserved_2, false, &buff_ptr);
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
#ifndef MINIVHD_STRUCT_RW_H
|
||||
#define MINIVHD_STRUCT_RW_H
|
||||
|
||||
#include "minivhd_internal.h"
|
||||
|
||||
/**
|
||||
* \brief Save the contents of a VHD footer from a buffer to a struct
|
||||
*
|
||||
* \param [out] footer save contents of buffer into footer
|
||||
* \param [in] buffer VHD footer in raw bytes
|
||||
*/
|
||||
void mvhd_buffer_to_footer(MVHDFooter* footer, uint8_t* buffer);
|
||||
|
||||
/**
|
||||
* \brief Save the contents of a VHD sparse header from a buffer to a struct
|
||||
*
|
||||
* \param [out] header save contents of buffer into header
|
||||
* \param [in] buffer VHD header in raw bytes
|
||||
*/
|
||||
void mvhd_buffer_to_header(MVHDSparseHeader* header, uint8_t* buffer);
|
||||
|
||||
/**
|
||||
* \brief Save the contents of a VHD footer struct to a buffer
|
||||
*
|
||||
* \param [in] footer save contents of struct into buffer
|
||||
* \param [out] buffer VHD footer in raw bytes
|
||||
*/
|
||||
void mvhd_footer_to_buffer(MVHDFooter* footer, uint8_t* buffer);
|
||||
|
||||
/**
|
||||
* \brief Save the contents of a VHD sparse header struct to a buffer
|
||||
*
|
||||
* \param [in] header save contents of struct into buffer
|
||||
* \param [out] buffer VHD sparse header in raw bytes
|
||||
*/
|
||||
void mvhd_header_to_buffer(MVHDSparseHeader* header, uint8_t* buffer);
|
||||
|
||||
#endif
|
||||
@@ -1,46 +1,90 @@
|
||||
/**
|
||||
* \file
|
||||
* \brief Utility functions
|
||||
/*
|
||||
* MiniVHD Minimalist VHD implementation in C.
|
||||
*
|
||||
* This file is part of the MiniVHD Project.
|
||||
*
|
||||
* Utility functions.
|
||||
*
|
||||
* Version: @(#)util.c 1.0.4 2021/04/16
|
||||
*
|
||||
* Author: Sherman Perry, <shermperry@gmail.com>
|
||||
*
|
||||
* Copyright 2019-2021 Sherman Perry.
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documenta-
|
||||
* tion files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall
|
||||
* be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF O R IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include "libxml2_encoding.h"
|
||||
#include "minivhd_internal.h"
|
||||
#include "minivhd_util.h"
|
||||
#include "minivhd.h"
|
||||
#include "internal.h"
|
||||
#include "xml2_encoding.h"
|
||||
|
||||
const char MVHD_CONECTIX_COOKIE[] = "conectix";
|
||||
const char MVHD_CREATOR[] = "pcem";
|
||||
const char MVHD_CREATOR_HOST_OS[] = "Wi2k";
|
||||
const char MVHD_CXSPARSE_COOKIE[] = "cxsparse";
|
||||
|
||||
uint16_t mvhd_from_be16(uint16_t val) {
|
||||
uint16_t
|
||||
mvhd_from_be16(uint16_t val)
|
||||
{
|
||||
uint8_t *tmp = (uint8_t*)&val;
|
||||
uint16_t ret = 0;
|
||||
|
||||
ret |= (uint16_t)tmp[0] << 8;
|
||||
ret |= (uint16_t)tmp[1] << 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
uint32_t mvhd_from_be32(uint32_t val) {
|
||||
|
||||
|
||||
uint32_t
|
||||
mvhd_from_be32(uint32_t val)
|
||||
{
|
||||
uint8_t *tmp = (uint8_t*)&val;
|
||||
uint32_t ret = 0;
|
||||
|
||||
ret = (uint32_t)tmp[0] << 24;
|
||||
ret |= (uint32_t)tmp[1] << 16;
|
||||
ret |= (uint32_t)tmp[2] << 8;
|
||||
ret |= (uint32_t)tmp[3] << 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
uint64_t mvhd_from_be64(uint64_t val) {
|
||||
|
||||
|
||||
uint64_t
|
||||
mvhd_from_be64(uint64_t val)
|
||||
{
|
||||
uint8_t *tmp = (uint8_t*)&val;
|
||||
uint64_t ret = 0;
|
||||
|
||||
ret = (uint64_t)tmp[0] << 56;
|
||||
ret |= (uint64_t)tmp[1] << 48;
|
||||
ret |= (uint64_t)tmp[2] << 40;
|
||||
@@ -49,27 +93,45 @@ uint64_t mvhd_from_be64(uint64_t val) {
|
||||
ret |= (uint64_t)tmp[5] << 16;
|
||||
ret |= (uint64_t)tmp[6] << 8;
|
||||
ret |= (uint64_t)tmp[7] << 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
uint16_t mvhd_to_be16(uint16_t val) {
|
||||
|
||||
|
||||
uint16_t
|
||||
mvhd_to_be16(uint16_t val)
|
||||
{
|
||||
uint16_t ret = 0;
|
||||
uint8_t *tmp = (uint8_t*)&ret;
|
||||
|
||||
tmp[0] = (val & 0xff00) >> 8;
|
||||
tmp[1] = (val & 0x00ff) >> 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
uint32_t mvhd_to_be32(uint32_t val) {
|
||||
|
||||
|
||||
uint32_t
|
||||
mvhd_to_be32(uint32_t val)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
uint8_t *tmp = (uint8_t*)&ret;
|
||||
|
||||
tmp[0] = (val & 0xff000000) >> 24;
|
||||
tmp[1] = (val & 0x00ff0000) >> 16;
|
||||
tmp[2] = (val & 0x0000ff00) >> 8;
|
||||
tmp[3] = (val & 0x000000ff) >> 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
uint64_t mvhd_to_be64(uint64_t val) {
|
||||
|
||||
|
||||
uint64_t
|
||||
mvhd_to_be64(uint64_t val)
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
uint8_t *tmp = (uint8_t*)&ret;
|
||||
|
||||
tmp[0] = (uint8_t)((val & 0xff00000000000000) >> 56);
|
||||
tmp[1] = (uint8_t)((val & 0x00ff000000000000) >> 48);
|
||||
tmp[2] = (uint8_t)((val & 0x0000ff0000000000) >> 40);
|
||||
@@ -78,21 +140,17 @@ uint64_t mvhd_to_be64(uint64_t val) {
|
||||
tmp[5] = (uint8_t)((val & 0x0000000000ff0000) >> 16);
|
||||
tmp[6] = (uint8_t)((val & 0x000000000000ff00) >> 8);
|
||||
tmp[7] = (uint8_t)((val & 0x00000000000000ff) >> 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool mvhd_is_conectix_str(const void* buffer) {
|
||||
if (strncmp(buffer, MVHD_CONECTIX_COOKIE, strlen(MVHD_CONECTIX_COOKIE)) == 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void mvhd_generate_uuid(uint8_t* uuid)
|
||||
void
|
||||
mvhd_generate_uuid(uint8_t* uuid)
|
||||
{
|
||||
/* We aren't doing crypto here, so using system time as seed should be good enough */
|
||||
srand((unsigned int)time(0));
|
||||
|
||||
for (int n = 0; n < 16; n++) {
|
||||
uuid[n] = rand();
|
||||
}
|
||||
@@ -102,34 +160,50 @@ void mvhd_generate_uuid(uint8_t* uuid)
|
||||
uuid[8] |= 0x80; /* Variant 1 */
|
||||
}
|
||||
|
||||
uint32_t vhd_calc_timestamp(void)
|
||||
{
|
||||
time_t start_time;
|
||||
time_t curr_time;
|
||||
double vhd_time;
|
||||
start_time = MVHD_START_TS; /* 1 Jan 2000 00:00 */
|
||||
curr_time = time(NULL);
|
||||
vhd_time = difftime(curr_time, start_time);
|
||||
return (uint32_t)vhd_time;
|
||||
}
|
||||
|
||||
uint32_t mvhd_epoch_to_vhd_ts(time_t ts) {
|
||||
time_t start_time = MVHD_START_TS;
|
||||
if (ts < start_time) {
|
||||
return start_time;
|
||||
}
|
||||
double vhd_time = difftime(ts, start_time);
|
||||
uint32_t
|
||||
vhd_calc_timestamp(void)
|
||||
{
|
||||
time_t start_time;
|
||||
time_t curr_time;
|
||||
double vhd_time;
|
||||
|
||||
start_time = MVHD_START_TS; /* 1 Jan 2000 00:00 */
|
||||
curr_time = time(NULL);
|
||||
vhd_time = difftime(curr_time, start_time);
|
||||
|
||||
return (uint32_t)vhd_time;
|
||||
}
|
||||
|
||||
time_t vhd_get_created_time(MVHDMeta *vhdm)
|
||||
|
||||
uint32_t
|
||||
mvhd_epoch_to_vhd_ts(time_t ts)
|
||||
{
|
||||
time_t vhd_time = (time_t)vhdm->footer.timestamp;
|
||||
time_t vhd_time_unix = MVHD_START_TS + vhd_time;
|
||||
return vhd_time_unix;
|
||||
time_t start_time = MVHD_START_TS;
|
||||
double vhd_time;
|
||||
|
||||
if (ts < start_time)
|
||||
return (uint32_t)start_time;
|
||||
|
||||
vhd_time = difftime(ts, start_time);
|
||||
|
||||
return (uint32_t)vhd_time;
|
||||
}
|
||||
|
||||
FILE* mvhd_fopen(const char* path, const char* mode, int* err) {
|
||||
|
||||
time_t
|
||||
vhd_get_created_time(MVHDMeta *vhdm)
|
||||
{
|
||||
time_t vhd_time = (time_t)vhdm->footer.timestamp;
|
||||
time_t vhd_time_unix = MVHD_START_TS + vhd_time;
|
||||
|
||||
return vhd_time_unix;
|
||||
}
|
||||
|
||||
|
||||
FILE*
|
||||
mvhd_fopen(const char* path, const char* mode, int* err)
|
||||
{
|
||||
FILE* f = NULL;
|
||||
#ifdef _WIN32
|
||||
size_t path_len = strlen(path);
|
||||
@@ -140,6 +214,7 @@ FILE* mvhd_fopen(const char* path, const char* mode, int* err) {
|
||||
int new_mode_len = (sizeof mode_str) - 2;
|
||||
int path_res = UTF8ToUTF16LE((unsigned char*)new_path, &new_path_len, (const unsigned char*)path, (int*)&path_len);
|
||||
int mode_res = UTF8ToUTF16LE((unsigned char*)mode_str, &new_mode_len, (const unsigned char*)mode, (int*)&mode_len);
|
||||
|
||||
if (path_res > 0 && mode_res > 0) {
|
||||
f = _wfopen(new_path, mode_str);
|
||||
if (f == NULL) {
|
||||
@@ -160,10 +235,14 @@ FILE* mvhd_fopen(const char* path, const char* mode, int* err) {
|
||||
*err = MVHD_ERR_FILE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
void mvhd_set_encoding_err(int encoding_retval, int* err) {
|
||||
|
||||
void
|
||||
mvhd_set_encoding_err(int encoding_retval, int* err)
|
||||
{
|
||||
if (encoding_retval == -1) {
|
||||
*err = MVHD_ERR_UTF_SIZE;
|
||||
} else if (encoding_retval == -2) {
|
||||
@@ -171,87 +250,162 @@ void mvhd_set_encoding_err(int encoding_retval, int* err) {
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t mvhd_calc_size_bytes(MVHDGeom *geom) {
|
||||
|
||||
uint64_t
|
||||
mvhd_calc_size_bytes(MVHDGeom *geom)
|
||||
{
|
||||
uint64_t img_size = (uint64_t)geom->cyl * (uint64_t)geom->heads * (uint64_t)geom->spt * (uint64_t)MVHD_SECTOR_SIZE;
|
||||
|
||||
return img_size;
|
||||
}
|
||||
|
||||
uint32_t mvhd_calc_size_sectors(MVHDGeom *geom) {
|
||||
|
||||
uint32_t
|
||||
mvhd_calc_size_sectors(MVHDGeom *geom)
|
||||
{
|
||||
uint32_t sector_size = (uint32_t)geom->cyl * (uint32_t)geom->heads * (uint32_t)geom->spt;
|
||||
|
||||
return sector_size;
|
||||
}
|
||||
|
||||
MVHDGeom mvhd_get_geometry(MVHDMeta* vhdm) {
|
||||
MVHDGeom geometry = { .cyl = vhdm->footer.geom.cyl, .heads = vhdm->footer.geom.heads, .spt = vhdm->footer.geom.spt };
|
||||
|
||||
MVHDAPI MVHDGeom
|
||||
mvhd_get_geometry(MVHDMeta* vhdm)
|
||||
{
|
||||
MVHDGeom geometry = {
|
||||
.cyl = vhdm->footer.geom.cyl,
|
||||
.heads = vhdm->footer.geom.heads,
|
||||
.spt = vhdm->footer.geom.spt
|
||||
};
|
||||
|
||||
return geometry;
|
||||
}
|
||||
|
||||
uint32_t mvhd_gen_footer_checksum(MVHDFooter* footer) {
|
||||
|
||||
MVHDAPI uint64_t
|
||||
mvhd_get_current_size(MVHDMeta* vhdm)
|
||||
{
|
||||
return vhdm->footer.curr_sz;
|
||||
}
|
||||
|
||||
|
||||
uint32_t
|
||||
mvhd_gen_footer_checksum(MVHDFooter* footer)
|
||||
{
|
||||
uint32_t new_chk = 0;
|
||||
uint32_t orig_chk = footer->checksum;
|
||||
footer->checksum = 0;
|
||||
uint8_t* footer_bytes = (uint8_t*)footer;
|
||||
for (size_t i = 0; i < sizeof *footer; i++) {
|
||||
|
||||
for (size_t i = 0; i < sizeof *footer; i++)
|
||||
new_chk += footer_bytes[i];
|
||||
}
|
||||
footer->checksum = orig_chk;
|
||||
|
||||
return ~new_chk;
|
||||
}
|
||||
|
||||
uint32_t mvhd_gen_sparse_checksum(MVHDSparseHeader* header) {
|
||||
|
||||
uint32_t
|
||||
mvhd_gen_sparse_checksum(MVHDSparseHeader* header)
|
||||
{
|
||||
uint32_t new_chk = 0;
|
||||
uint32_t orig_chk = header->checksum;
|
||||
header->checksum = 0;
|
||||
uint8_t* sparse_bytes = (uint8_t*)header;
|
||||
|
||||
for (size_t i = 0; i < sizeof *header; i++) {
|
||||
new_chk += sparse_bytes[i];
|
||||
}
|
||||
header->checksum = orig_chk;
|
||||
|
||||
return ~new_chk;
|
||||
}
|
||||
|
||||
const char* mvhd_strerr(MVHDError err) {
|
||||
|
||||
MVHDAPI const char*
|
||||
mvhd_strerr(MVHDError err)
|
||||
{
|
||||
const char *s = "unknown error";
|
||||
|
||||
switch (err) {
|
||||
case MVHD_ERR_MEM:
|
||||
return "memory allocation error";
|
||||
case MVHD_ERR_FILE:
|
||||
return "file error";
|
||||
case MVHD_ERR_NOT_VHD:
|
||||
return "file is not a VHD image";
|
||||
case MVHD_ERR_TYPE:
|
||||
return "unsupported VHD image type";
|
||||
case MVHD_ERR_FOOTER_CHECKSUM:
|
||||
return "invalid VHD footer checksum";
|
||||
case MVHD_ERR_SPARSE_CHECKSUM:
|
||||
return "invalid VHD sparse header checksum";
|
||||
case MVHD_ERR_UTF_TRANSCODING_FAILED:
|
||||
return "error converting path encoding";
|
||||
case MVHD_ERR_UTF_SIZE:
|
||||
return "buffer size mismatch when converting path encoding";
|
||||
case MVHD_ERR_PATH_REL:
|
||||
return "relative path detected where absolute path expected";
|
||||
case MVHD_ERR_PATH_LEN:
|
||||
return "path length exceeds MVHD_MAX_PATH";
|
||||
case MVHD_ERR_PAR_NOT_FOUND:
|
||||
return "parent VHD image not found";
|
||||
case MVHD_ERR_INVALID_PAR_UUID:
|
||||
return "UUID mismatch between child and parent VHD";
|
||||
case MVHD_ERR_INVALID_GEOM:
|
||||
return "invalid geometry detected";
|
||||
case MVHD_ERR_INVALID_SIZE:
|
||||
return "invalid size";
|
||||
case MVHD_ERR_INVALID_BLOCK_SIZE:
|
||||
return "invalid block size";
|
||||
case MVHD_ERR_INVALID_PARAMS:
|
||||
return "invalid parameters passed to function";
|
||||
case MVHD_ERR_CONV_SIZE:
|
||||
return "error converting image. Size mismatch detechted";
|
||||
default:
|
||||
return "unknown error";
|
||||
case MVHD_ERR_MEM:
|
||||
s = "memory allocation error";
|
||||
break;
|
||||
|
||||
case MVHD_ERR_FILE:
|
||||
s = "file error";
|
||||
break;
|
||||
|
||||
case MVHD_ERR_NOT_VHD:
|
||||
s = "file is not a VHD image";
|
||||
break;
|
||||
|
||||
case MVHD_ERR_TYPE:
|
||||
s = "unsupported VHD image type";
|
||||
break;
|
||||
|
||||
case MVHD_ERR_FOOTER_CHECKSUM:
|
||||
s = "invalid VHD footer checksum";
|
||||
break;
|
||||
|
||||
case MVHD_ERR_SPARSE_CHECKSUM:
|
||||
s = "invalid VHD sparse header checksum";
|
||||
break;
|
||||
|
||||
case MVHD_ERR_UTF_TRANSCODING_FAILED:
|
||||
s = "error converting path encoding";
|
||||
break;
|
||||
|
||||
case MVHD_ERR_UTF_SIZE:
|
||||
s = "buffer size mismatch when converting path encoding";
|
||||
break;
|
||||
|
||||
case MVHD_ERR_PATH_REL:
|
||||
s = "relative path detected where absolute path expected";
|
||||
break;
|
||||
|
||||
case MVHD_ERR_PATH_LEN:
|
||||
s = "path length exceeds MVHD_MAX_PATH";
|
||||
break;
|
||||
|
||||
case MVHD_ERR_PAR_NOT_FOUND:
|
||||
s = "parent VHD image not found";
|
||||
break;
|
||||
|
||||
case MVHD_ERR_INVALID_PAR_UUID:
|
||||
s = "UUID mismatch between child and parent VHD";
|
||||
break;
|
||||
|
||||
case MVHD_ERR_INVALID_GEOM:
|
||||
s = "invalid geometry detected";
|
||||
break;
|
||||
|
||||
case MVHD_ERR_INVALID_SIZE:
|
||||
s = "invalid size";
|
||||
break;
|
||||
|
||||
case MVHD_ERR_INVALID_BLOCK_SIZE:
|
||||
s = "invalid block size";
|
||||
break;
|
||||
|
||||
case MVHD_ERR_INVALID_PARAMS:
|
||||
s = "invalid parameters passed to function";
|
||||
break;
|
||||
|
||||
case MVHD_ERR_CONV_SIZE:
|
||||
s = "error converting image. Size mismatch detected";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int64_t mvhd_ftello64(FILE* stream)
|
||||
|
||||
int64_t
|
||||
mvhd_ftello64(FILE* stream)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _ftelli64(stream);
|
||||
@@ -262,7 +416,9 @@ int64_t mvhd_ftello64(FILE* stream)
|
||||
#endif
|
||||
}
|
||||
|
||||
int mvhd_fseeko64(FILE* stream, int64_t offset, int origin)
|
||||
|
||||
int
|
||||
mvhd_fseeko64(FILE* stream, int64_t offset, int origin)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _fseeki64(stream, offset, origin);
|
||||
@@ -273,17 +429,25 @@ int mvhd_fseeko64(FILE* stream, int64_t offset, int origin)
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t mvhd_crc32_for_byte(uint32_t r) {
|
||||
|
||||
uint32_t
|
||||
mvhd_crc32_for_byte(uint32_t r)
|
||||
{
|
||||
for (int j = 0; j < 8; ++j)
|
||||
r = (r & 1 ? 0 : (uint32_t)0xEDB88320L) ^ r >> 1;
|
||||
|
||||
return r ^ (uint32_t)0xFF000000L;
|
||||
}
|
||||
|
||||
uint32_t mvhd_crc32(const void* data, size_t n_bytes) {
|
||||
|
||||
uint32_t
|
||||
mvhd_crc32(const void* data, size_t n_bytes)
|
||||
{
|
||||
static uint32_t table[0x100];
|
||||
|
||||
if (!*table)
|
||||
for (size_t i = 0; i < 0x100; ++i)
|
||||
table[i] = mvhd_crc32_for_byte(i);
|
||||
table[i] = mvhd_crc32_for_byte((uint32_t)i);
|
||||
|
||||
uint32_t crc = 0;
|
||||
for (size_t i = 0; i < n_bytes; ++i)
|
||||
@@ -292,7 +456,10 @@ uint32_t mvhd_crc32(const void* data, size_t n_bytes) {
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint32_t mvhd_file_mod_timestamp(const char* path, int *err) {
|
||||
|
||||
uint32_t
|
||||
mvhd_file_mod_timestamp(const char* path, int *err)
|
||||
{
|
||||
*err = 0;
|
||||
#ifdef _WIN32
|
||||
struct _stat file_stat;
|
||||
@@ -300,6 +467,7 @@ uint32_t mvhd_file_mod_timestamp(const char* path, int *err) {
|
||||
mvhd_utf16 new_path[260] = {0};
|
||||
int new_path_len = (sizeof new_path) - 2;
|
||||
int path_res = UTF8ToUTF16LE((unsigned char*)new_path, &new_path_len, (const unsigned char*)path, (int*)&path_len);
|
||||
|
||||
if (path_res > 0) {
|
||||
int stat_res = _wstat(new_path, &file_stat);
|
||||
if (stat_res != 0) {
|
||||
@@ -319,6 +487,7 @@ uint32_t mvhd_file_mod_timestamp(const char* path, int *err) {
|
||||
#else
|
||||
struct stat file_stat;
|
||||
int stat_res = stat(path, &file_stat);
|
||||
|
||||
if (stat_res != 0) {
|
||||
mvhd_errno = errno;
|
||||
*err = MVHD_ERR_FILE;
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
#ifndef MINIVHD_UTIL_H
|
||||
#define MINIVHD_UTIL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include "minivhd_internal.h"
|
||||
#include "minivhd.h"
|
||||
#define MVHD_START_TS 946684800
|
||||
|
||||
/**
|
||||
* Functions to deal with endian issues
|
||||
*/
|
||||
uint16_t mvhd_from_be16(uint16_t val);
|
||||
uint32_t mvhd_from_be32(uint32_t val);
|
||||
uint64_t mvhd_from_be64(uint64_t val);
|
||||
uint16_t mvhd_to_be16(uint16_t val);
|
||||
uint32_t mvhd_to_be32(uint32_t val);
|
||||
uint64_t mvhd_to_be64(uint64_t val);
|
||||
|
||||
/**
|
||||
* \brief Check if provided buffer begins with the string "conectix"
|
||||
*
|
||||
* \param [in] buffer The buffer to compare. Must be at least 8 bytes in length
|
||||
*
|
||||
* \return true if the buffer begins with "conectix"
|
||||
* \return false if the buffer does not begin with "conectix"
|
||||
*/
|
||||
bool mvhd_is_conectix_str(const void* buffer);
|
||||
|
||||
/**
|
||||
* \brief Generate a raw 16 byte UUID
|
||||
*
|
||||
* \param [out] uuid A 16 byte buffer in which the generated UUID will be stored to
|
||||
*/
|
||||
void mvhd_generate_uuid(uint8_t *uuid);
|
||||
|
||||
/**
|
||||
* \brief Calculate a VHD formatted timestamp from the current time
|
||||
*/
|
||||
uint32_t vhd_calc_timestamp(void);
|
||||
|
||||
/**
|
||||
* \brief Convert an epoch timestamp to a VHD timestamp
|
||||
*
|
||||
* \param [in] ts epoch timestamp to convert.
|
||||
*
|
||||
* \return The adjusted timestamp, or 0 if the input timestamp is
|
||||
* earlier that 1 Janurary 2000
|
||||
*/
|
||||
uint32_t mvhd_epoch_to_vhd_ts(time_t ts);
|
||||
|
||||
/**
|
||||
* \brief Return the created time from a VHD image
|
||||
*
|
||||
* \param [in] vhdm Pointer to the MiniVHD metadata structure
|
||||
*
|
||||
* \return The created time, as a Unix timestamp
|
||||
*/
|
||||
time_t vhd_get_created_time(MVHDMeta *vhdm);
|
||||
|
||||
/**
|
||||
* \brief Cross platform, unicode filepath opening
|
||||
*
|
||||
* This function accounts for the fact that fopen() handles file paths differently compared to other
|
||||
* operating systems. Windows version of fopen() will not handle multi byte encoded text like UTF-8.
|
||||
*
|
||||
* Unicode filepath support on Windows requires using the _wfopen() function, which expects UTF-16LE
|
||||
* encoded path and modestring.
|
||||
*
|
||||
* \param [in] path The filepath to open as a UTF-8 string
|
||||
* \param [in] mode The mode string to use (eg: "rb+"")
|
||||
* \param [out] err The error value, if an error occurrs
|
||||
*
|
||||
* \return a FILE pointer if successful, NULL otherwise. If NULL, check the value of err
|
||||
*/
|
||||
FILE* mvhd_fopen(const char* path, const char* mode, int* err);
|
||||
|
||||
void mvhd_set_encoding_err(int encoding_retval, int* err);
|
||||
uint64_t mvhd_calc_size_bytes(MVHDGeom *geom);
|
||||
uint32_t mvhd_calc_size_sectors(MVHDGeom *geom);
|
||||
MVHDGeom mvhd_get_geometry(MVHDMeta* vhdm);
|
||||
|
||||
/**
|
||||
* \brief Generate VHD footer checksum
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
uint32_t mvhd_gen_footer_checksum(MVHDFooter* footer);
|
||||
|
||||
/**
|
||||
* \brief Generate VHD sparse header checksum
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
uint32_t mvhd_gen_sparse_checksum(MVHDSparseHeader* header);
|
||||
|
||||
/**
|
||||
* \brief Get current position in file stream
|
||||
*
|
||||
* This is a portable version of the POSIX ftello64(). *
|
||||
*/
|
||||
int64_t mvhd_ftello64(FILE* stream);
|
||||
|
||||
/**
|
||||
* \brief Reposition the file stream's position
|
||||
*
|
||||
* This is a portable version of the POSIX fseeko64(). *
|
||||
*/
|
||||
int mvhd_fseeko64(FILE* stream, int64_t offset, int origin);
|
||||
|
||||
/**
|
||||
* \brief Calculate the CRC32 of a data buffer.
|
||||
*
|
||||
* This function can be used for verifying data integrity.
|
||||
*
|
||||
* \param [in] data The data buffer
|
||||
* \param [in] n_bytes The size of the data buffer in bytes
|
||||
*
|
||||
* \return The CRC32 of the data buffer
|
||||
*/
|
||||
uint32_t mvhd_crc32(const void* data, size_t n_bytes);
|
||||
|
||||
/**
|
||||
* \brief Calculate the file modification timestamp.
|
||||
*
|
||||
* This function is primarily to help protect differencing VHD's
|
||||
*
|
||||
* \param [in] path the UTF-8 file path
|
||||
* \param [out] err The error value, if an error occurrs
|
||||
*
|
||||
* \return The file modified timestamp, in VHD compatible timestamp.
|
||||
* 'err' will be set to non-zero on error
|
||||
*/
|
||||
uint32_t mvhd_file_mod_timestamp(const char* path, int *err);
|
||||
#endif
|
||||
232
src/disk/minivhd/struct_rw.c
Normal file
232
src/disk/minivhd/struct_rw.c
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* MiniVHD Minimalist VHD implementation in C.
|
||||
*
|
||||
* This file is part of the MiniVHD Project.
|
||||
*
|
||||
* Header and footer serialize/deserialize functions.
|
||||
*
|
||||
* Read data from footer into the struct members, swapping
|
||||
* endian where necessary.
|
||||
*
|
||||
* NOTE: Order matters here!
|
||||
* We must read each field in the order the struct is in.
|
||||
* Doing this may be less elegant than performing a memcpy
|
||||
* to a packed struct, but it avoids potential data alignment
|
||||
* issues, and the endian swapping allows us to use the fields
|
||||
* directly.
|
||||
*
|
||||
* Version: @(#)struct_rw.c 1.0.2 2021/04/16
|
||||
*
|
||||
* Author: Sherman Perry, <shermperry@gmail.com>
|
||||
*
|
||||
* Copyright 2019-2021 Sherman Perry.
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documenta-
|
||||
* tion files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall
|
||||
* be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF O R IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "minivhd.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
/**
|
||||
* \brief Get the next field from a buffer and store it in a struct member, converting endian if necessary
|
||||
*
|
||||
* \param [out] struct_memb struct member to save the field to
|
||||
* \param [in] memb_size the size of struct_memb, in bytes
|
||||
* \param [in] req_endian is the field a value that requires endian conversion (eg: uint16, uint32)
|
||||
* \param [in] buffer the buffer from which fields are read from. Will be advanced at the end of the function call
|
||||
*/
|
||||
static void
|
||||
next_buffer_to_struct(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer)
|
||||
{
|
||||
memcpy(struct_memb, *buffer, memb_size);
|
||||
|
||||
if (req_endian) switch (memb_size) {
|
||||
case 2:
|
||||
*(uint16_t*)(struct_memb) = mvhd_from_be16(*(uint16_t*)(struct_memb));
|
||||
break;
|
||||
|
||||
case 4:
|
||||
*(uint32_t*)(struct_memb) = mvhd_from_be32(*(uint32_t*)(struct_memb));
|
||||
break;
|
||||
|
||||
case 8:
|
||||
*(uint64_t*)(struct_memb) = mvhd_from_be64(*(uint64_t*)(struct_memb));
|
||||
break;
|
||||
}
|
||||
|
||||
*buffer += memb_size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Save a struct member into a buffer, converting endian if necessary
|
||||
*
|
||||
* \param [in] struct_memb struct member read from
|
||||
* \param [in] memb_size the size of struct_memb, in bytes
|
||||
* \param [in] req_endian is the field a value that requires endian conversion (eg: uint16, uint32)
|
||||
* \param [out] buffer the buffer from which struct member is saved to. Will be advanced at the end of the function call
|
||||
*/
|
||||
static void
|
||||
next_struct_to_buffer(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer)
|
||||
{
|
||||
uint8_t *buf_ptr = *buffer;
|
||||
|
||||
memcpy(buf_ptr, struct_memb, memb_size);
|
||||
|
||||
if (req_endian) switch (memb_size) {
|
||||
case 2:
|
||||
*((uint16_t*)buf_ptr) = mvhd_to_be16(*(uint16_t*)(struct_memb));
|
||||
break;
|
||||
|
||||
case 4:
|
||||
*((uint32_t*)buf_ptr) = mvhd_to_be32(*(uint32_t*)(struct_memb));
|
||||
break;
|
||||
|
||||
case 8:
|
||||
*((uint64_t*)buf_ptr) = mvhd_to_be64(*(uint64_t*)(struct_memb));
|
||||
break;
|
||||
}
|
||||
|
||||
buf_ptr += memb_size;
|
||||
*buffer = buf_ptr;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
mvhd_buffer_to_footer(MVHDFooter* footer, uint8_t* buffer)
|
||||
{
|
||||
uint8_t* buff_ptr = buffer;
|
||||
|
||||
next_buffer_to_struct(&footer->cookie, sizeof footer->cookie, false, &buff_ptr);
|
||||
next_buffer_to_struct(&footer->features, sizeof footer->features, true, &buff_ptr);
|
||||
next_buffer_to_struct(&footer->fi_fmt_vers, sizeof footer->fi_fmt_vers, true, &buff_ptr);
|
||||
next_buffer_to_struct(&footer->data_offset, sizeof footer->data_offset, true, &buff_ptr);
|
||||
next_buffer_to_struct(&footer->timestamp, sizeof footer->timestamp, true, &buff_ptr);
|
||||
next_buffer_to_struct(&footer->cr_app, sizeof footer->cr_app, false, &buff_ptr);
|
||||
next_buffer_to_struct(&footer->cr_vers, sizeof footer->cr_vers, true, &buff_ptr);
|
||||
next_buffer_to_struct(&footer->cr_host_os, sizeof footer->cr_host_os, false, &buff_ptr);
|
||||
next_buffer_to_struct(&footer->orig_sz, sizeof footer->orig_sz, true, &buff_ptr);
|
||||
next_buffer_to_struct(&footer->curr_sz, sizeof footer->curr_sz, true, &buff_ptr);
|
||||
next_buffer_to_struct(&footer->geom.cyl, sizeof footer->geom.cyl, true, &buff_ptr);
|
||||
next_buffer_to_struct(&footer->geom.heads, sizeof footer->geom.heads, false, &buff_ptr);
|
||||
next_buffer_to_struct(&footer->geom.spt, sizeof footer->geom.spt, false, &buff_ptr);
|
||||
next_buffer_to_struct(&footer->disk_type, sizeof footer->disk_type, true, &buff_ptr);
|
||||
next_buffer_to_struct(&footer->checksum, sizeof footer->checksum, true, &buff_ptr);
|
||||
next_buffer_to_struct(&footer->uuid, sizeof footer->uuid, false, &buff_ptr);
|
||||
next_buffer_to_struct(&footer->saved_st, sizeof footer->saved_st, false, &buff_ptr);
|
||||
next_buffer_to_struct(&footer->reserved, sizeof footer->reserved, false, &buff_ptr);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
mvhd_footer_to_buffer(MVHDFooter* footer, uint8_t* buffer)
|
||||
{
|
||||
uint8_t* buff_ptr = buffer;
|
||||
|
||||
next_struct_to_buffer(&footer->cookie, sizeof footer->cookie, false, &buff_ptr);
|
||||
next_struct_to_buffer(&footer->features, sizeof footer->features, true, &buff_ptr);
|
||||
next_struct_to_buffer(&footer->fi_fmt_vers, sizeof footer->fi_fmt_vers, true, &buff_ptr);
|
||||
next_struct_to_buffer(&footer->data_offset, sizeof footer->data_offset, true, &buff_ptr);
|
||||
next_struct_to_buffer(&footer->timestamp, sizeof footer->timestamp, true, &buff_ptr);
|
||||
next_struct_to_buffer(&footer->cr_app, sizeof footer->cr_app, false, &buff_ptr);
|
||||
next_struct_to_buffer(&footer->cr_vers, sizeof footer->cr_vers, true, &buff_ptr);
|
||||
next_struct_to_buffer(&footer->cr_host_os, sizeof footer->cr_host_os, false, &buff_ptr);
|
||||
next_struct_to_buffer(&footer->orig_sz, sizeof footer->orig_sz, true, &buff_ptr);
|
||||
next_struct_to_buffer(&footer->curr_sz, sizeof footer->curr_sz, true, &buff_ptr);
|
||||
next_struct_to_buffer(&footer->geom.cyl, sizeof footer->geom.cyl, true, &buff_ptr);
|
||||
next_struct_to_buffer(&footer->geom.heads, sizeof footer->geom.heads, false, &buff_ptr);
|
||||
next_struct_to_buffer(&footer->geom.spt, sizeof footer->geom.spt, false, &buff_ptr);
|
||||
next_struct_to_buffer(&footer->disk_type, sizeof footer->disk_type, true, &buff_ptr);
|
||||
next_struct_to_buffer(&footer->checksum, sizeof footer->checksum, true, &buff_ptr);
|
||||
next_struct_to_buffer(&footer->uuid, sizeof footer->uuid, false, &buff_ptr);
|
||||
next_struct_to_buffer(&footer->saved_st, sizeof footer->saved_st, false, &buff_ptr);
|
||||
next_struct_to_buffer(&footer->reserved, sizeof footer->reserved, false, &buff_ptr);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
mvhd_buffer_to_header(MVHDSparseHeader* header, uint8_t* buffer)
|
||||
{
|
||||
uint8_t* buff_ptr = buffer;
|
||||
|
||||
next_buffer_to_struct(&header->cookie, sizeof header->cookie, false, &buff_ptr);
|
||||
next_buffer_to_struct(&header->data_offset, sizeof header->data_offset, true, &buff_ptr);
|
||||
next_buffer_to_struct(&header->bat_offset, sizeof header->bat_offset, true, &buff_ptr);
|
||||
next_buffer_to_struct(&header->head_vers, sizeof header->head_vers, true, &buff_ptr);
|
||||
next_buffer_to_struct(&header->max_bat_ent, sizeof header->max_bat_ent, true, &buff_ptr);
|
||||
next_buffer_to_struct(&header->block_sz, sizeof header->block_sz, true, &buff_ptr);
|
||||
next_buffer_to_struct(&header->checksum, sizeof header->checksum, true, &buff_ptr);
|
||||
next_buffer_to_struct(&header->par_uuid, sizeof header->par_uuid, false, &buff_ptr);
|
||||
next_buffer_to_struct(&header->par_timestamp, sizeof header->par_timestamp, true, &buff_ptr);
|
||||
next_buffer_to_struct(&header->reserved_1, sizeof header->reserved_1, true, &buff_ptr);
|
||||
next_buffer_to_struct(&header->par_utf16_name, sizeof header->par_utf16_name, false, &buff_ptr);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
next_buffer_to_struct(&header->par_loc_entry[i].plat_code, sizeof header->par_loc_entry[i].plat_code, true, &buff_ptr);
|
||||
next_buffer_to_struct(&header->par_loc_entry[i].plat_data_space, sizeof header->par_loc_entry[i].plat_data_space, true, &buff_ptr);
|
||||
next_buffer_to_struct(&header->par_loc_entry[i].plat_data_len, sizeof header->par_loc_entry[i].plat_data_len, true, &buff_ptr);
|
||||
next_buffer_to_struct(&header->par_loc_entry[i].reserved, sizeof header->par_loc_entry[i].reserved, true, &buff_ptr);
|
||||
next_buffer_to_struct(&header->par_loc_entry[i].plat_data_offset, sizeof header->par_loc_entry[i].plat_data_offset, true, &buff_ptr);
|
||||
}
|
||||
|
||||
next_buffer_to_struct(&header->reserved_2, sizeof header->reserved_2, false, &buff_ptr);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
mvhd_header_to_buffer(MVHDSparseHeader* header, uint8_t* buffer)
|
||||
{
|
||||
uint8_t* buff_ptr = buffer;
|
||||
|
||||
next_struct_to_buffer(&header->cookie, sizeof header->cookie, false, &buff_ptr);
|
||||
next_struct_to_buffer(&header->data_offset, sizeof header->data_offset, true, &buff_ptr);
|
||||
next_struct_to_buffer(&header->bat_offset, sizeof header->bat_offset, true, &buff_ptr);
|
||||
next_struct_to_buffer(&header->head_vers, sizeof header->head_vers, true, &buff_ptr);
|
||||
next_struct_to_buffer(&header->max_bat_ent, sizeof header->max_bat_ent, true, &buff_ptr);
|
||||
next_struct_to_buffer(&header->block_sz, sizeof header->block_sz, true, &buff_ptr);
|
||||
next_struct_to_buffer(&header->checksum, sizeof header->checksum, true, &buff_ptr);
|
||||
next_struct_to_buffer(&header->par_uuid, sizeof header->par_uuid, false, &buff_ptr);
|
||||
next_struct_to_buffer(&header->par_timestamp, sizeof header->par_timestamp, true, &buff_ptr);
|
||||
next_struct_to_buffer(&header->reserved_1, sizeof header->reserved_1, true, &buff_ptr);
|
||||
next_struct_to_buffer(&header->par_utf16_name, sizeof header->par_utf16_name, false, &buff_ptr);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
next_struct_to_buffer(&header->par_loc_entry[i].plat_code, sizeof header->par_loc_entry[i].plat_code, true, &buff_ptr);
|
||||
next_struct_to_buffer(&header->par_loc_entry[i].plat_data_space, sizeof header->par_loc_entry[i].plat_data_space, true, &buff_ptr);
|
||||
next_struct_to_buffer(&header->par_loc_entry[i].plat_data_len, sizeof header->par_loc_entry[i].plat_data_len, true, &buff_ptr);
|
||||
next_struct_to_buffer(&header->par_loc_entry[i].reserved, sizeof header->par_loc_entry[i].reserved, true, &buff_ptr);
|
||||
next_struct_to_buffer(&header->par_loc_entry[i].plat_data_offset, sizeof header->par_loc_entry[i].plat_data_offset, true, &buff_ptr);
|
||||
}
|
||||
|
||||
next_struct_to_buffer(&header->reserved_2, sizeof header->reserved_2, false, &buff_ptr);
|
||||
}
|
||||
68
src/disk/minivhd/version.h
Normal file
68
src/disk/minivhd/version.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* MiniVHD Minimalist VHD implementation in C.
|
||||
*
|
||||
* This file is part of the MiniVHD Project.
|
||||
*
|
||||
* Define library version and build info.
|
||||
*
|
||||
* Version: @(#)version.h 1.034 2021/04/16
|
||||
*
|
||||
* Author: Fred N. van Kempen, <waltje@varcem.com>
|
||||
*
|
||||
* Copyright 2021 Fred N. van Kempen.
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documenta-
|
||||
* tion files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall
|
||||
* be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF O R IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MINIVHD_VERSION_H
|
||||
# define MINIVHD_VERSION_H
|
||||
|
||||
|
||||
/* Library name. */
|
||||
#define LIB_NAME "MiniVHD"
|
||||
|
||||
/* Version info. */
|
||||
#define LIB_VER_MAJOR 1
|
||||
#define LIB_VER_MINOR 0
|
||||
#define LIB_VER_REV 3
|
||||
#define LIB_VER_PATCH 0
|
||||
|
||||
|
||||
/* Standard C preprocessor macros. */
|
||||
#define STR_STRING(x) #x
|
||||
#define STR(x) STR_STRING(x)
|
||||
#define STR_RC(a,e) a ## , ## e
|
||||
|
||||
|
||||
/* These are used in the application. */
|
||||
#define LIB_VER_NUM LIB_VER_MAJOR.LIB_VER_MINOR.LIB_VER_REV
|
||||
#if defined(LIB_VER_PATCH) && LIB_VER_PATCH > 0
|
||||
# define LIB_VER_NUM_4 LIB_VER_MAJOR.LIB_VER_MINOR.LIB_VER_REV.LIB_VER_PATCH
|
||||
#else
|
||||
# define LIB_VER_NUM_4 LIB_VER_MAJOR.LIB_VER_MINOR.LIB_VER_REV.0
|
||||
#endif
|
||||
#define LIB_VERSION STR(LIB_VER_NUM)
|
||||
#define LIB_VERSION_4 STR(LIB_VER_NUM_4)
|
||||
|
||||
|
||||
#endif /*MINIVHD_VERSION_H*/
|
||||
@@ -22,9 +22,19 @@
|
||||
* Adapted and abridged for MiniVHD by Sherman Perry
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#define BUILDING_LIBRARY
|
||||
#include "minivhd.h"
|
||||
#include "internal.h"
|
||||
#include "xml2_encoding.h"
|
||||
|
||||
|
||||
static int xmlLittleEndian = 1;
|
||||
|
||||
|
||||
/* Note: extracted from original 'void xmlInitCharEncodingHandlers(void)' function */
|
||||
void xmlEncodingInit(void)
|
||||
{
|
||||
@@ -96,8 +106,8 @@ int UTF16LEToUTF8(unsigned char* out, int *outlen,
|
||||
c += 0x10000;
|
||||
}
|
||||
else {
|
||||
*outlen = out - outstart;
|
||||
*inlenb = processed - inb;
|
||||
*outlen = (int)(out - outstart);
|
||||
*inlenb = (int)(processed - inb);
|
||||
return(-2);
|
||||
}
|
||||
}
|
||||
@@ -117,8 +127,8 @@ int UTF16LEToUTF8(unsigned char* out, int *outlen,
|
||||
}
|
||||
processed = (const unsigned char*) in;
|
||||
}
|
||||
*outlen = out - outstart;
|
||||
*inlenb = processed - inb;
|
||||
*outlen = (int)(out - outstart);
|
||||
*inlenb = (int)(processed - inb);
|
||||
return(*outlen);
|
||||
}
|
||||
|
||||
@@ -163,16 +173,16 @@ int UTF8ToUTF16LE(unsigned char* outb, int *outlen,
|
||||
if (d < 0x80) { c= d; trailing= 0; }
|
||||
else if (d < 0xC0) {
|
||||
/* trailing byte in leading position */
|
||||
*outlen = (out - outstart) * 2;
|
||||
*inlen = processed - instart;
|
||||
*outlen = (int)((out - outstart) * 2);
|
||||
*inlen = (int)(processed - instart);
|
||||
return(-2);
|
||||
} else if (d < 0xE0) { c= d & 0x1F; trailing= 1; }
|
||||
else if (d < 0xF0) { c= d & 0x0F; trailing= 2; }
|
||||
else if (d < 0xF8) { c= d & 0x07; trailing= 3; }
|
||||
else {
|
||||
/* no chance for this in UTF-16 */
|
||||
*outlen = (out - outstart) * 2;
|
||||
*inlen = processed - instart;
|
||||
*outlen = (int)((out - outstart) * 2);
|
||||
*inlen = (int)(processed - instart);
|
||||
return(-2);
|
||||
}
|
||||
|
||||
@@ -225,8 +235,8 @@ int UTF8ToUTF16LE(unsigned char* outb, int *outlen,
|
||||
break;
|
||||
processed = in;
|
||||
}
|
||||
*outlen = (out - outstart) * 2;
|
||||
*inlen = processed - instart;
|
||||
*outlen = (int)((out - outstart) * 2);
|
||||
*inlen = (int)(processed - instart);
|
||||
return(*outlen);
|
||||
}
|
||||
|
||||
@@ -275,8 +285,8 @@ int UTF16BEToUTF8(unsigned char* out, int *outlen,
|
||||
}
|
||||
if ((c & 0xFC00) == 0xD800) { /* surrogates */
|
||||
if (in >= inend) { /* (in > inend) shouldn't happens */
|
||||
*outlen = out - outstart;
|
||||
*inlenb = processed - inb;
|
||||
*outlen = (int)(out - outstart);
|
||||
*inlenb = (int)(processed - inb);
|
||||
return(-2);
|
||||
}
|
||||
if (xmlLittleEndian) {
|
||||
@@ -295,8 +305,8 @@ int UTF16BEToUTF8(unsigned char* out, int *outlen,
|
||||
c += 0x10000;
|
||||
}
|
||||
else {
|
||||
*outlen = out - outstart;
|
||||
*inlenb = processed - inb;
|
||||
*outlen = (int)(out - outstart);
|
||||
*inlenb = (int)(processed - inb);
|
||||
return(-2);
|
||||
}
|
||||
}
|
||||
@@ -316,8 +326,8 @@ int UTF16BEToUTF8(unsigned char* out, int *outlen,
|
||||
}
|
||||
processed = (const unsigned char*) in;
|
||||
}
|
||||
*outlen = out - outstart;
|
||||
*inlenb = processed - inb;
|
||||
*outlen = (int)(out - outstart);
|
||||
*inlenb = (int)(processed - inb);
|
||||
return(*outlen);
|
||||
}
|
||||
|
||||
@@ -362,16 +372,16 @@ int UTF8ToUTF16BE(unsigned char* outb, int *outlen,
|
||||
if (d < 0x80) { c= d; trailing= 0; }
|
||||
else if (d < 0xC0) {
|
||||
/* trailing byte in leading position */
|
||||
*outlen = out - outstart;
|
||||
*inlen = processed - instart;
|
||||
*outlen = (int)(out - outstart);
|
||||
*inlen = (int)(processed - instart);
|
||||
return(-2);
|
||||
} else if (d < 0xE0) { c= d & 0x1F; trailing= 1; }
|
||||
else if (d < 0xF0) { c= d & 0x0F; trailing= 2; }
|
||||
else if (d < 0xF8) { c= d & 0x07; trailing= 3; }
|
||||
else {
|
||||
/* no chance for this in UTF-16 */
|
||||
*outlen = out - outstart;
|
||||
*inlen = processed - instart;
|
||||
*outlen = (int)(out - outstart);
|
||||
*inlen = (int)(processed - instart);
|
||||
return(-2);
|
||||
}
|
||||
|
||||
@@ -421,8 +431,8 @@ int UTF8ToUTF16BE(unsigned char* outb, int *outlen,
|
||||
break;
|
||||
processed = in;
|
||||
}
|
||||
*outlen = (out - outstart) * 2;
|
||||
*inlen = processed - instart;
|
||||
*outlen = (int)((out - outstart) * 2);
|
||||
*inlen = (int)(processed - instart);
|
||||
return(*outlen);
|
||||
}
|
||||
|
||||
62
src/disk/minivhd/xml2_encoding.h
Normal file
62
src/disk/minivhd/xml2_encoding.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* MiniVHD Minimalist VHD implementation in C.
|
||||
*
|
||||
* This file is part of the MiniVHD Project.
|
||||
*
|
||||
* Version: @(#)xml2_encoding.h 1.0.1 2021/03/15
|
||||
*
|
||||
* Author: Sherman Perry, <shermperry@gmail.com>
|
||||
*
|
||||
* Copyright 2019-2021 Sherman Perry.
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documenta-
|
||||
* tion files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall
|
||||
* be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF O R IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef XML2_ENCODING_H
|
||||
# define XML2_ENCODING_H
|
||||
|
||||
|
||||
typedef uint16_t mvhd_utf16;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void xmlEncodingInit(void);
|
||||
|
||||
int UTF16LEToUTF8(uint8_t *out, int *outlen, const uint8_t *inb,
|
||||
int *inlenb);
|
||||
int UTF8ToUTF16LE(uint8_t *outb, int *outlen, const uint8_t *in,
|
||||
int *inlen);
|
||||
int UTF16BEToUTF8(uint8_t *out, int *outlen, const uint8_t *inb,
|
||||
int *inlenb);
|
||||
int UTF8ToUTF16BE(uint8_t *outb, int *outlen, const uint8_t *in,
|
||||
int *inlen);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*XML2_ENCODING_H*/
|
||||
@@ -33,12 +33,12 @@
|
||||
#include <86box/fdc.h>
|
||||
#include <86box/fdc_ext.h>
|
||||
|
||||
#define BIOS_ADDR (uint32_t)(device_get_config_hex20("bios_addr") & 0x000fffff)
|
||||
#define BIOS_ADDR (uint32_t)(device_get_config_hex20("bios_addr") & 0x000fffff)
|
||||
#define ROM_MONSTER_FDC "roms/floppy/monster-fdc/floppy_bios.bin"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rom_t bios_rom;
|
||||
rom_t bios_rom;
|
||||
fdc_t *fdc_pri;
|
||||
fdc_t *fdc_sec;
|
||||
} monster_fdc_t;
|
||||
@@ -46,7 +46,7 @@ typedef struct
|
||||
static void
|
||||
monster_fdc_close(void *priv)
|
||||
{
|
||||
monster_fdc_t *dev = (monster_fdc_t *)priv;
|
||||
monster_fdc_t *dev = (monster_fdc_t *) priv;
|
||||
|
||||
free(dev);
|
||||
}
|
||||
@@ -56,7 +56,7 @@ monster_fdc_init(const device_t *info)
|
||||
{
|
||||
monster_fdc_t *dev;
|
||||
|
||||
dev = (monster_fdc_t *)malloc(sizeof(monster_fdc_t));
|
||||
dev = (monster_fdc_t *) malloc(sizeof(monster_fdc_t));
|
||||
memset(dev, 0, sizeof(monster_fdc_t));
|
||||
|
||||
#if 0
|
||||
@@ -86,13 +86,14 @@ monster_fdc_init(const device_t *info)
|
||||
return dev;
|
||||
}
|
||||
|
||||
static int monster_fdc_available(void)
|
||||
static int
|
||||
monster_fdc_available(void)
|
||||
{
|
||||
return rom_present(ROM_MONSTER_FDC);
|
||||
}
|
||||
|
||||
static const device_config_t monster_fdc_config[] = {
|
||||
// clang-format off
|
||||
// clang-format off
|
||||
#if 0
|
||||
{
|
||||
.name = "sec_enabled",
|
||||
@@ -205,19 +206,19 @@ static const device_config_t monster_fdc_config[] = {
|
||||
},
|
||||
#endif
|
||||
{ .name = "", .description = "", .type = CONFIG_END }
|
||||
// clang-format on
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
const device_t fdc_monster_device = {
|
||||
.name = "Monster FDC Floppy Drive Controller",
|
||||
.name = "Monster FDC Floppy Drive Controller",
|
||||
.internal_name = "monster_fdc",
|
||||
.flags = DEVICE_ISA,
|
||||
.local = 0,
|
||||
.init = monster_fdc_init,
|
||||
.close = monster_fdc_close,
|
||||
.reset = NULL,
|
||||
.flags = DEVICE_ISA,
|
||||
.local = 0,
|
||||
.init = monster_fdc_init,
|
||||
.close = monster_fdc_close,
|
||||
.reset = NULL,
|
||||
{ .available = monster_fdc_available },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config =monster_fdc_config
|
||||
.force_redraw = NULL,
|
||||
.config = monster_fdc_config
|
||||
};
|
||||
|
||||
@@ -1520,7 +1520,7 @@ struct pulse_sample {
|
||||
static int pulse_limitval = 15; /* tolerance of 15% */
|
||||
static struct pulse_sample psarray[FDI_MAX_ARRAY];
|
||||
static int array_index;
|
||||
static uint32_t total;
|
||||
static uint32_t total;
|
||||
static int totaldiv;
|
||||
|
||||
static void
|
||||
@@ -2051,7 +2051,7 @@ decode_lowlevel_track(FDI *fdi, int track, struct fdi_cache *cache)
|
||||
}
|
||||
|
||||
static unsigned char fdiid[] = { "Formatted Disk Image file" };
|
||||
static int bit_rate_table[16] = { 125, 150, 250, 300, 500, 1000 };
|
||||
static int bit_rate_table[16] = { 125, 150, 250, 300, 500, 1000 };
|
||||
|
||||
void
|
||||
fdi2raw_header_free(FDI *fdi)
|
||||
|
||||
@@ -427,16 +427,16 @@ tmacm_init(const device_t *info)
|
||||
|
||||
port = device_get_config_hex16("port2_addr");
|
||||
switch (port) {
|
||||
case 0x201:
|
||||
case 0x209:
|
||||
dev = gameport_add(&gameport_209_device);
|
||||
break;
|
||||
case 0x203:
|
||||
case 0x20b:
|
||||
dev = gameport_add(&gameport_20b_device);
|
||||
break;
|
||||
case 0x205:
|
||||
case 0x20d:
|
||||
dev = gameport_add(&gameport_20d_device);
|
||||
break;
|
||||
case 0x207:
|
||||
case 0x20f:
|
||||
dev = gameport_add(&gameport_20f_device);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -22,6 +22,52 @@
|
||||
#ifndef EMU_KEYBOARD_H
|
||||
#define EMU_KEYBOARD_H
|
||||
|
||||
enum {
|
||||
DEV_KBD = 0,
|
||||
DEV_AUX
|
||||
};
|
||||
|
||||
/* Used by the AT / PS/2 keyboard controller, common device, keyboard, and mouse. */
|
||||
typedef struct {
|
||||
uint8_t wantcmd, dat, pad, pad0;
|
||||
|
||||
int out_new;
|
||||
|
||||
void *priv;
|
||||
|
||||
void (*poll)(void *priv);
|
||||
} kbc_port_t;
|
||||
|
||||
/* Used by the AT / PS/2 common device, keyboard, and mouse. */
|
||||
typedef struct {
|
||||
const char *name; /* name of this device */
|
||||
|
||||
uint8_t type, inst, command, wantdata,
|
||||
last_scan_code, state, resolution, rate,
|
||||
cmd_queue_start, cmd_queue_end, queue_start, queue_end;
|
||||
|
||||
/* 6 bytes needed for mouse */
|
||||
uint8_t last_data[6];
|
||||
|
||||
uint16_t flags;
|
||||
|
||||
/* Internal FIFO, not present on real devices, needed for commands that
|
||||
output multiple bytes. */
|
||||
uint8_t cmd_queue[16];
|
||||
|
||||
uint8_t queue[16];
|
||||
|
||||
int mode,
|
||||
x, y, z, b;
|
||||
|
||||
int *scan;
|
||||
|
||||
void (*process_cmd)(void *priv);
|
||||
void (*execute_bat)(void *priv);
|
||||
|
||||
kbc_port_t *port;
|
||||
} atkbc_dev_t;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t mk[4];
|
||||
const uint8_t brk[4];
|
||||
@@ -139,8 +185,11 @@ extern uint8_t keyboard_set3_flags[512];
|
||||
extern uint8_t keyboard_set3_all_repeat;
|
||||
extern uint8_t keyboard_set3_all_break;
|
||||
extern int mouse_queue_start, mouse_queue_end;
|
||||
extern int mouse_cmd_queue_start, mouse_cmd_queue_end;
|
||||
extern int mouse_scan;
|
||||
|
||||
extern kbc_port_t *kbc_ports[2];
|
||||
|
||||
#ifdef EMU_DEVICE_H
|
||||
extern const device_t keyboard_pc_device;
|
||||
extern const device_t keyboard_pc82_device;
|
||||
@@ -152,13 +201,13 @@ extern const device_t keyboard_xt_t1x00_device;
|
||||
extern const device_t keyboard_tandy_device;
|
||||
# if defined(DEV_BRANCH) && defined(USE_LASERXT)
|
||||
extern const device_t keyboard_xt_lxt3_device;
|
||||
# endif
|
||||
# endif /*defined(DEV_BRANCH) && defined(USE_LASERXT) */
|
||||
extern const device_t keyboard_xt_olivetti_device;
|
||||
extern const device_t keyboard_xt_zenith_device;
|
||||
extern const device_t keyboard_xtclone_device;
|
||||
extern const device_t keyboard_at_device;
|
||||
extern const device_t keyboard_at_ami_device;
|
||||
extern const device_t keyboard_at_samsung_device;
|
||||
extern const device_t keyboard_at_tg_ami_device;
|
||||
extern const device_t keyboard_at_toshiba_device;
|
||||
extern const device_t keyboard_at_olivetti_device;
|
||||
extern const device_t keyboard_at_ncr_device;
|
||||
@@ -167,6 +216,8 @@ extern const device_t keyboard_ps2_ps1_device;
|
||||
extern const device_t keyboard_ps2_ps1_pci_device;
|
||||
extern const device_t keyboard_ps2_xi8088_device;
|
||||
extern const device_t keyboard_ps2_ami_device;
|
||||
extern const device_t keyboard_ps2_tg_ami_device;
|
||||
extern const device_t keyboard_ps2_tg_ami_green_device;
|
||||
extern const device_t keyboard_ps2_olivetti_device;
|
||||
extern const device_t keyboard_ps2_mca_device;
|
||||
extern const device_t keyboard_ps2_mca_2_device;
|
||||
@@ -176,7 +227,8 @@ extern const device_t keyboard_ps2_ami_pci_device;
|
||||
extern const device_t keyboard_ps2_intel_ami_pci_device;
|
||||
extern const device_t keyboard_ps2_acer_pci_device;
|
||||
extern const device_t keyboard_ps2_ali_pci_device;
|
||||
#endif
|
||||
extern const device_t keyboard_ps2_tg_ami_pci_device;
|
||||
#endif /*EMU_DEVICE_H*/
|
||||
|
||||
extern void keyboard_init(void);
|
||||
extern void keyboard_close(void);
|
||||
@@ -190,22 +242,21 @@ extern uint8_t keyboard_get_shift(void);
|
||||
extern void keyboard_get_states(uint8_t *cl, uint8_t *nl, uint8_t *sl);
|
||||
extern void keyboard_set_states(uint8_t cl, uint8_t nl, uint8_t sl);
|
||||
extern int keyboard_recv(uint16_t key);
|
||||
extern int keyboard_isfsenter(void);
|
||||
extern int keyboard_isfsenter_down(void);
|
||||
extern int keyboard_isfsexit(void);
|
||||
extern int keyboard_isfsexit_down(void);
|
||||
extern int keyboard_ismsexit(void);
|
||||
extern void keyboard_set_is_amstrad(int ams);
|
||||
|
||||
extern void keyboard_at_adddata_mouse(uint8_t val);
|
||||
extern void keyboard_at_adddata_mouse_direct(uint8_t val);
|
||||
extern void keyboard_at_adddata_mouse_cmd(uint8_t val);
|
||||
extern void keyboard_at_mouse_reset(void);
|
||||
extern uint8_t keyboard_at_mouse_pos(void);
|
||||
extern int keyboard_at_fixed_channel(void);
|
||||
extern void keyboard_at_set_mouse(void (*mouse_write)(uint8_t val, void *), void *);
|
||||
extern void keyboard_at_set_a20_key(int state);
|
||||
extern void keyboard_at_set_mode(int ps2);
|
||||
extern uint8_t keyboard_at_get_mouse_scan(void);
|
||||
extern void keyboard_at_set_mouse_scan(uint8_t val);
|
||||
extern void keyboard_at_reset(void);
|
||||
extern void kbc_at_a20_reset(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -162,6 +162,7 @@
|
||||
#else
|
||||
# define IDS_DYNAREC IDS_2163
|
||||
#endif
|
||||
#define IDS_2166 2166 // "Video card #2 ""%hs"" is not..."
|
||||
|
||||
#define IDS_4096 4096 // "Hard disk (%s)"
|
||||
#define IDS_4097 4097 // "%01i:%01i"
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#define MOUSE_TYPE_LT3BUTTON 10 /* Logitech 3-button Serial Mouse */
|
||||
#define MOUSE_TYPE_PS2 11 /* PS/2 series Bus Mouse */
|
||||
#define MOUSE_TYPE_WACOM 12 /* WACOM tablet */
|
||||
#define MOUSE_TYPE_WACOMARTP 13 /* WACOM tablet (ArtPad) */
|
||||
|
||||
#define MOUSE_TYPE_ONBOARD 0x80 /* Mouse is an on-board version of one of the above. */
|
||||
|
||||
@@ -65,6 +66,7 @@ extern const device_t mouse_msserial_device;
|
||||
extern const device_t mouse_ltserial_device;
|
||||
extern const device_t mouse_ps2_device;
|
||||
extern const device_t mouse_wacom_device;
|
||||
extern const device_t mouse_wacom_artpad_device;
|
||||
#endif
|
||||
|
||||
extern void mouse_init(void);
|
||||
|
||||
@@ -43,8 +43,11 @@ extern void pic_elcr_write(uint16_t port, uint8_t val, void *priv);
|
||||
extern uint8_t pic_elcr_read(uint16_t port, void *priv);
|
||||
|
||||
extern void pic_set_shadow(int sh);
|
||||
extern int pic_get_pci_flag(void);
|
||||
extern void pic_set_pci_flag(int pci);
|
||||
extern void pic_set_pci(void);
|
||||
extern void pic_kbd_latch(int enable);
|
||||
extern void pic_mouse_latch(int enable);
|
||||
extern void pic_init(void);
|
||||
extern void pic_init_pcjr(void);
|
||||
extern void pic2_init(void);
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#define MPU401_VERSION 0x15
|
||||
#define MPU401_REVISION 0x01
|
||||
#define MPU401_QUEUE 64
|
||||
#define MPU401_QUEUE 1024
|
||||
#define MPU401_INPUT_QUEUE 1024
|
||||
#define MPU401_TIMECONSTANT (60000000 / 1000.0f)
|
||||
#define MPU401_RESETBUSY 27.0f
|
||||
|
||||
@@ -24,9 +24,16 @@
|
||||
|
||||
extern int sound_gain;
|
||||
|
||||
#define SOUNDBUFLEN (48000 / 50)
|
||||
#define FREQ_44100 44100
|
||||
#define FREQ_48000 48000
|
||||
#define FREQ_49716 49716
|
||||
#define FREQ_88200 88200
|
||||
#define FREQ_96000 96000
|
||||
|
||||
#define CD_FREQ 44100
|
||||
#define SOUND_FREQ FREQ_48000
|
||||
#define SOUNDBUFLEN (SOUND_FREQ / 50)
|
||||
|
||||
#define CD_FREQ FREQ_44100
|
||||
#define CD_BUFLEN (CD_FREQ / 10)
|
||||
|
||||
enum {
|
||||
|
||||
@@ -113,6 +113,7 @@ extern int con, cursoron, cgablink;
|
||||
extern int scrollcache;
|
||||
|
||||
extern uint8_t edatlookup[4][4];
|
||||
extern uint8_t egaremap2bpp[256];
|
||||
|
||||
#if defined(EMU_MEM_H) && defined(EMU_ROM_H)
|
||||
void ega_render_blank(ega_t *ega);
|
||||
@@ -120,14 +121,8 @@ void ega_render_blank(ega_t *ega);
|
||||
void ega_render_overscan_left(ega_t *ega);
|
||||
void ega_render_overscan_right(ega_t *ega);
|
||||
|
||||
void ega_render_text_40(ega_t *ega);
|
||||
void ega_render_text_80(ega_t *ega);
|
||||
|
||||
void ega_render_2bpp_lowres(ega_t *ega);
|
||||
void ega_render_2bpp_highres(ega_t *ega);
|
||||
|
||||
void ega_render_4bpp_lowres(ega_t *ega);
|
||||
void ega_render_4bpp_highres(ega_t *ega);
|
||||
void ega_render_text(ega_t *ega);
|
||||
void ega_render_graphics(ega_t *ega);
|
||||
#endif
|
||||
|
||||
#endif /*VIDEO_EGA_H*/
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
break; \
|
||||
\
|
||||
case VAR_WORD_MODE_MA13: \
|
||||
out_addr = ((in_addr << 1) & 0x1fff8) | ((in_addr >> 13) & 0x4) | (in_addr & ~0x1ffff); \
|
||||
out_addr = ((in_addr << 1) & 0x3fff8) | ((in_addr >> 13) & 0x4) | (in_addr & ~0x3ffff); \
|
||||
break; \
|
||||
\
|
||||
case VAR_WORD_MODE_MA15: \
|
||||
out_addr = ((in_addr << 1) & 0x1fff8) | ((in_addr >> 15) & 0x4) | (in_addr & ~0x1ffff); \
|
||||
out_addr = ((in_addr << 1) & 0x3fff8) | ((in_addr >> 15) & 0x4) | (in_addr & ~0x3ffff); \
|
||||
break; \
|
||||
\
|
||||
case VAR_DWORD_MODE: \
|
||||
@@ -85,7 +85,7 @@ ega_recalc_remap_func(ega_t *ega)
|
||||
func_nr = VAR_DWORD_MODE;
|
||||
else if (ega->crtc[0x17] & 0x40)
|
||||
func_nr = VAR_BYTE_MODE;
|
||||
else if (ega->crtc[0x17] & 0x20)
|
||||
else if ((ega->crtc[0x17] & 0x20) && ega->vram_limit > 64*1024)
|
||||
func_nr = VAR_WORD_MODE_MA15;
|
||||
else
|
||||
func_nr = VAR_WORD_MODE_MA13;
|
||||
|
||||
25
src/io.c
25
src/io.c
@@ -56,6 +56,7 @@ typedef struct {
|
||||
int initialized = 0;
|
||||
io_t *io[NPORTS], *io_last[NPORTS];
|
||||
|
||||
// #define ENABLE_IO_LOG 1
|
||||
#ifdef ENABLE_IO_LOG
|
||||
int io_do_log = ENABLE_IO_LOG;
|
||||
|
||||
@@ -310,7 +311,9 @@ inb(uint16_t port)
|
||||
/* if (port == 0x1ed)
|
||||
ret = 0xfe; */
|
||||
|
||||
io_log("[%04X:%08X] (%i, %i, %04i) in b(%04X) = %02X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret);
|
||||
if (port == 0x92) {
|
||||
io_log("[%04X:%08X] (%i, %i, %04i) in b(%04X) = %02X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret);
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
@@ -341,7 +344,9 @@ outb(uint16_t port, uint8_t val)
|
||||
#endif
|
||||
}
|
||||
|
||||
io_log("[%04X:%08X] (%i, %i, %04i) outb(%04X, %02X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val);
|
||||
if (port == 0x92) {
|
||||
io_log("[%04X:%08X] (%i, %i, %04i) outb(%04X, %02X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -395,7 +400,9 @@ inw(uint16_t port)
|
||||
if (!found)
|
||||
cycles -= io_delay;
|
||||
|
||||
io_log("[%04X:%08X] (%i, %i, %04i) in w(%04X) = %04X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret);
|
||||
if (port == 0x92) {
|
||||
io_log("[%04X:%08X] (%i, %i, %04i) in w(%04X) = %04X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -440,7 +447,9 @@ outw(uint16_t port, uint16_t val)
|
||||
#endif
|
||||
}
|
||||
|
||||
io_log("[%04X:%08X] (%i, %i, %04i) outw(%04X, %04X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val);
|
||||
if (port == 0x92) {
|
||||
io_log("[%04X:%08X] (%i, %i, %04i) outw(%04X, %04X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -522,7 +531,9 @@ inl(uint16_t port)
|
||||
if (!found)
|
||||
cycles -= io_delay;
|
||||
|
||||
io_log("[%04X:%08X] (%i, %i, %04i) in l(%04X) = %08X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret);
|
||||
if (port == 0x92) {
|
||||
io_log("[%04X:%08X] (%i, %i, %04i) in l(%04X) = %08X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -582,7 +593,9 @@ outl(uint16_t port, uint32_t val)
|
||||
#endif
|
||||
}
|
||||
|
||||
io_log("[%04X:%08X] (%i, %i, %04i) outl(%04X, %08X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val);
|
||||
if (port == 0x92) {
|
||||
io_log("[%04X:%08X] (%i, %i, %04i) outl(%04X, %08X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -220,7 +220,7 @@ machine_at_spc6000a_init(const machine_t *model)
|
||||
if (fdc_type == FDC_INTERNAL)
|
||||
device_add(&fdc_at_device);
|
||||
|
||||
device_add(&keyboard_at_samsung_device);
|
||||
device_add(&keyboard_at_ami_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -404,7 +404,7 @@ machine_at_acerv10_init(const machine_t *model)
|
||||
machine_at_common_init(model);
|
||||
|
||||
device_add(&sis_85c461_device);
|
||||
device_add(&keyboard_ps2_ami_pci_device);
|
||||
device_add(&keyboard_ps2_acer_pci_device);
|
||||
device_add(&ide_isa_2ch_device);
|
||||
|
||||
if (fdc_type == FDC_INTERNAL)
|
||||
@@ -1066,7 +1066,7 @@ machine_at_486sp3_init(const machine_t *model)
|
||||
pci_register_slot(0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); /* 05 = Slot 3 */
|
||||
pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); /* 06 = Slot 4 */
|
||||
pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0);
|
||||
device_add(&keyboard_ps2_ami_pci_device); /* Uses the AMIKEY KBC */
|
||||
device_add(&keyboard_ps2_ami_pci_device); /* Uses the AMIKEY KBC */
|
||||
device_add(&sio_device);
|
||||
device_add(&fdc37c663_ide_device);
|
||||
device_add(&sst_flash_29ee010_device);
|
||||
@@ -1657,7 +1657,7 @@ machine_at_actionpc2600_init(const machine_t *model)
|
||||
device_add(&umc_8886af_device);
|
||||
device_add(&um8669f_device);
|
||||
device_add(&intel_flash_bxt_device);
|
||||
device_add(&keyboard_at_ami_device);
|
||||
device_add(&keyboard_ps2_tg_ami_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1725,11 +1725,11 @@ machine_at_ms4134_init(const machine_t *model)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = bios_load_linear("roms/machines/ms4134/4alm001.bin",
|
||||
ret = bios_load_linear("roms/machines/ms4134/4alm001.bin",
|
||||
0x000e0000, 131072, 0);
|
||||
|
||||
if (bios_only || !ret)
|
||||
return ret;
|
||||
return ret;
|
||||
|
||||
machine_at_common_ide_init(model);
|
||||
|
||||
@@ -1760,10 +1760,10 @@ machine_at_tg486gp_init(const machine_t *model)
|
||||
int ret;
|
||||
|
||||
ret = bios_load_linear("roms/machines/tg486gp/tg486gp.bin",
|
||||
0x000e0000, 131072, 0);
|
||||
0x000e0000, 131072, 0);
|
||||
|
||||
if (bios_only || !ret)
|
||||
return ret;
|
||||
return ret;
|
||||
|
||||
machine_at_common_ide_init(model);
|
||||
|
||||
@@ -1782,7 +1782,7 @@ machine_at_tg486gp_init(const machine_t *model)
|
||||
device_add(&ali1435_device);
|
||||
device_add(&sst_flash_29ee010_device);
|
||||
|
||||
device_add(&keyboard_ps2_ami_device);
|
||||
device_add(&keyboard_ps2_tg_ami_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1793,10 +1793,10 @@ machine_at_tg486g_init(const machine_t *model)
|
||||
int ret;
|
||||
|
||||
ret = bios_load_linear("roms/machines/tg486g/tg486g.bin",
|
||||
0x000c0000, 262144, 0);
|
||||
0x000c0000, 262144, 0);
|
||||
|
||||
if (bios_only || !ret)
|
||||
return ret;
|
||||
return ret;
|
||||
else {
|
||||
mem_mapping_set_addr(&bios_mapping, 0x0c0000, 0x40000);
|
||||
mem_mapping_set_exec(&bios_mapping, rom);
|
||||
@@ -1806,7 +1806,7 @@ machine_at_tg486g_init(const machine_t *model)
|
||||
device_add(&sis_85c471_device);
|
||||
device_add(&ide_isa_device);
|
||||
device_add(&fdc37c651_ide_device);
|
||||
device_add(&keyboard_ps2_intel_ami_pci_device);
|
||||
device_add(&keyboard_ps2_tg_ami_pci_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ machine_at_hawk_init(const machine_t *model)
|
||||
pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1);
|
||||
pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2);
|
||||
pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0);
|
||||
device_add(&keyboard_ps2_ami_pci_device);
|
||||
device_add(&keyboard_ps2_tg_ami_pci_device);
|
||||
device_add(&i430fx_device);
|
||||
device_add(&piix_device);
|
||||
device_add(&fdc37c665_device);
|
||||
|
||||
@@ -1343,6 +1343,9 @@ machine_ps2_common_init(const machine_t *model)
|
||||
nmi_mask = 0x80;
|
||||
|
||||
ps2.uart = device_add_inst(&ns16550_device, 1);
|
||||
|
||||
pic_kbd_latch(0x01);
|
||||
pic_mouse_latch(0x01);
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
@@ -136,6 +136,22 @@ laserxt_init(int is_lxt3)
|
||||
laserxt_is_lxt3 = is_lxt3;
|
||||
}
|
||||
|
||||
static void
|
||||
machine_xt_laserxt_common_init(const machine_t *model,int is_lxt3)
|
||||
{
|
||||
machine_common_init(model);
|
||||
|
||||
pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt);
|
||||
|
||||
if (fdc_type == FDC_INTERNAL)
|
||||
device_add(&fdc_xt_device);
|
||||
|
||||
nmi_init();
|
||||
standalone_gameport_type = &gameport_device;
|
||||
|
||||
laserxt_init(is_lxt3);
|
||||
}
|
||||
|
||||
int
|
||||
machine_xt_laserxt_init(const machine_t *model)
|
||||
{
|
||||
@@ -147,9 +163,9 @@ machine_xt_laserxt_init(const machine_t *model)
|
||||
if (bios_only || !ret)
|
||||
return ret;
|
||||
|
||||
machine_xt_init(model);
|
||||
device_add(&keyboard_xt_device);
|
||||
|
||||
laserxt_init(0);
|
||||
machine_xt_laserxt_common_init(model, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -165,18 +181,9 @@ machine_xt_lxt3_init(const machine_t *model)
|
||||
if (bios_only || !ret)
|
||||
return ret;
|
||||
|
||||
machine_common_init(model);
|
||||
|
||||
pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt);
|
||||
|
||||
device_add(&keyboard_xt_lxt3_device);
|
||||
|
||||
if (fdc_type == FDC_INTERNAL)
|
||||
device_add(&fdc_xt_device);
|
||||
nmi_init();
|
||||
standalone_gameport_type = &gameport_device;
|
||||
|
||||
laserxt_init(1);
|
||||
machine_xt_laserxt_common_init(model, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3774,7 +3774,7 @@ const machine_t machines[] = {
|
||||
.min_multi = 0,
|
||||
.max_multi = 0
|
||||
},
|
||||
.bus_flags = MACHINE_PS2,
|
||||
.bus_flags = MACHINE_AT,
|
||||
.flags = MACHINE_IDE,
|
||||
.ram = {
|
||||
.min = 1024,
|
||||
@@ -3813,7 +3813,7 @@ const machine_t machines[] = {
|
||||
.min_multi = 0,
|
||||
.max_multi = 0
|
||||
},
|
||||
.bus_flags = MACHINE_PS2,
|
||||
.bus_flags = MACHINE_AT,
|
||||
.flags = MACHINE_IDE,
|
||||
.ram = {
|
||||
.min = 1024,
|
||||
@@ -3894,7 +3894,7 @@ const machine_t machines[] = {
|
||||
.min_multi = 0,
|
||||
.max_multi = 0
|
||||
},
|
||||
.bus_flags = MACHINE_PS2,
|
||||
.bus_flags = MACHINE_AT,
|
||||
.flags = MACHINE_IDE,
|
||||
.ram = {
|
||||
.min = 1024,
|
||||
@@ -7036,7 +7036,7 @@ const machine_t machines[] = {
|
||||
.min_multi = 0,
|
||||
.max_multi = 0
|
||||
},
|
||||
.bus_flags = MACHINE_PCI,
|
||||
.bus_flags = MACHINE_PS2_PCI,
|
||||
.flags = MACHINE_IDE_DUAL | MACHINE_APM,
|
||||
.ram = {
|
||||
.min = 1024,
|
||||
@@ -13005,7 +13005,6 @@ machine_get_kbc_device(int m)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
const device_t *
|
||||
machine_get_device(int m)
|
||||
{
|
||||
|
||||
@@ -2445,6 +2445,56 @@ mem_mapping_recalc(uint64_t base, uint64_t size)
|
||||
}
|
||||
|
||||
flushmmucache_cr3();
|
||||
|
||||
#ifdef ENABLE_MEM_LOG
|
||||
pclog("\nMemory map:\n");
|
||||
mem_mapping_t *write = (mem_mapping_t *) -1, *read = (mem_mapping_t *) -1, *write_bus = (mem_mapping_t *) -1, *read_bus = (mem_mapping_t *) -1;
|
||||
for (c = 0; c < (sizeof(write_mapping) / sizeof(write_mapping[0])); c++) {
|
||||
if ((write_mapping[c] == write) && (read_mapping[c] == read) && (write_mapping_bus[c] == write_bus) && (read_mapping_bus[c] == read_bus))
|
||||
continue;
|
||||
write = write_mapping[c];
|
||||
read = read_mapping[c];
|
||||
write_bus = write_mapping_bus[c];
|
||||
read_bus = read_mapping_bus[c];
|
||||
|
||||
pclog("%08X | ", c << MEM_GRANULARITY_BITS);
|
||||
if (read) {
|
||||
pclog("R%c%c%c %08X+% 8X",
|
||||
read->read_b ? 'b' : ' ', read->read_w ? 'w' : ' ', read->read_l ? 'l' : ' ',
|
||||
read->base, read->size);
|
||||
} else {
|
||||
pclog(" ");
|
||||
}
|
||||
if (write) {
|
||||
pclog(" | W%c%c%c %08X+% 8X",
|
||||
write->write_b ? 'b' : ' ', write->write_w ? 'w' : ' ', write->write_l ? 'l' : ' ',
|
||||
write->base, write->size);
|
||||
} else {
|
||||
pclog(" | ");
|
||||
}
|
||||
pclog(" | %c\n", _mem_exec[c] ? 'X' : ' ');
|
||||
|
||||
if ((write != write_bus) || (read != read_bus)) {
|
||||
pclog(" ^ bus | ");
|
||||
if (read_bus) {
|
||||
pclog("R%c%c%c %08X+% 8X",
|
||||
read_bus->read_b ? 'b' : ' ', read_bus->read_w ? 'w' : ' ', read_bus->read_l ? 'l' : ' ',
|
||||
read_bus->base, read_bus->size);
|
||||
} else {
|
||||
pclog(" ");
|
||||
}
|
||||
if (write_bus) {
|
||||
pclog(" | W%c%c%c %08X+% 8X",
|
||||
write_bus->write_b ? 'b' : ' ', write_bus->write_w ? 'w' : ' ', write_bus->write_l ? 'l' : ' ',
|
||||
write_bus->base, write_bus->size);
|
||||
} else {
|
||||
pclog(" | ");
|
||||
}
|
||||
pclog(" |\n");
|
||||
}
|
||||
}
|
||||
pclog("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2662,11 +2712,12 @@ void
|
||||
mem_a20_init(void)
|
||||
{
|
||||
if (is286) {
|
||||
rammask = cpu_16bitbus ? 0xefffff : 0xffefffff;
|
||||
mem_a20_key = mem_a20_alt = mem_a20_state = 0;
|
||||
rammask = cpu_16bitbus ? 0xffffff : 0xffffffff;
|
||||
if (is6117)
|
||||
rammask |= 0x03000000;
|
||||
flushmmucache();
|
||||
mem_a20_state = mem_a20_key | mem_a20_alt;
|
||||
// mem_a20_state = mem_a20_key | mem_a20_alt;
|
||||
} else {
|
||||
rammask = 0xfffff;
|
||||
flushmmucache();
|
||||
@@ -2709,7 +2760,8 @@ mem_init_ram_mapping(mem_mapping_t *mapping, uint32_t base, uint32_t size)
|
||||
void
|
||||
mem_reset(void)
|
||||
{
|
||||
uint32_t c, m;
|
||||
uint32_t c;
|
||||
size_t m;
|
||||
|
||||
memset(page_ff, 0xff, sizeof(page_ff));
|
||||
|
||||
@@ -2747,7 +2799,7 @@ mem_reset(void)
|
||||
mem_size = 2097152;
|
||||
#endif
|
||||
|
||||
m = 1024UL * mem_size;
|
||||
m = 1024UL * (size_t) mem_size;
|
||||
|
||||
#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64))
|
||||
if (mem_size > 1048576) {
|
||||
@@ -2963,6 +3015,10 @@ mem_remap_top(int kb)
|
||||
sis_mode = 1;
|
||||
}
|
||||
|
||||
/* Do not remap if we're have more than (16 MB - RAM) memory. */
|
||||
if ((kb != 0) && (mem_size >= (16384 - kb)))
|
||||
return;
|
||||
|
||||
if (kb == 0) {
|
||||
kb = old_kb;
|
||||
set = 0;
|
||||
|
||||
@@ -60,43 +60,42 @@
|
||||
#include <86box/bswap.h>
|
||||
|
||||
/* Maximum number of times we report a link down to the guest (failure to send frame) */
|
||||
#define ELNK_MAX_LINKDOWN_REPORTED 3
|
||||
#define ELNK_MAX_LINKDOWN_REPORTED 3
|
||||
|
||||
/* Maximum number of times we postpone restoring a link that is temporarily down. */
|
||||
#define ELNK_MAX_LINKRST_POSTPONED 3
|
||||
#define ELNK_MAX_LINKRST_POSTPONED 3
|
||||
|
||||
/* Maximum frame size we handle */
|
||||
#define MAX_FRAME 1536
|
||||
#define MAX_FRAME 1536
|
||||
|
||||
/* Size of the packet buffer. */
|
||||
#define ELNK_BUF_SIZE 2048
|
||||
#define ELNK_BUF_SIZE 2048
|
||||
|
||||
/* The packet buffer address mask. */
|
||||
#define ELNK_BUF_ADR_MASK (ELNK_BUF_SIZE - 1)
|
||||
#define ELNK_BUF_ADR_MASK (ELNK_BUF_SIZE - 1)
|
||||
|
||||
/* The GP buffer pointer address within the buffer. */
|
||||
#define ELNK_GP(dev) (dev->uGPBufPtr & ELNK_BUF_ADR_MASK)
|
||||
#define ELNK_GP(dev) (dev->uGPBufPtr & ELNK_BUF_ADR_MASK)
|
||||
|
||||
/* The GP buffer pointer mask.
|
||||
* NB: The GP buffer pointer is internally a 12-bit counter. When addressing into the
|
||||
* packet buffer, bit 11 is ignored. Required to pass 3C501 diagnostics.
|
||||
*/
|
||||
#define ELNK_GP_MASK 0xfff
|
||||
#define ELNK_GP_MASK 0xfff
|
||||
|
||||
/*********************************************************************************************************************************
|
||||
* Structures and Typedefs *
|
||||
*********************************************************************************************************************************/
|
||||
|
||||
* Structures and Typedefs *
|
||||
*********************************************************************************************************************************/
|
||||
|
||||
/**
|
||||
* EtherLink Transmit Command Register.
|
||||
*/
|
||||
typedef struct ELNK_XMIT_CMD {
|
||||
uint8_t det_ufl : 1; /* Detect underflow. */
|
||||
uint8_t det_coll : 1; /* Detect collision. */
|
||||
uint8_t det_16col : 1; /* Detect collision 16. */
|
||||
uint8_t det_succ : 1; /* Detect successful xmit. */
|
||||
uint8_t unused : 4;
|
||||
uint8_t det_ufl : 1; /* Detect underflow. */
|
||||
uint8_t det_coll : 1; /* Detect collision. */
|
||||
uint8_t det_16col : 1; /* Detect collision 16. */
|
||||
uint8_t det_succ : 1; /* Detect successful xmit. */
|
||||
uint8_t unused : 4;
|
||||
} EL_XMT_CMD;
|
||||
|
||||
/**
|
||||
@@ -107,151 +106,151 @@ typedef struct ELNK_XMIT_CMD {
|
||||
* (something the 3C501 does not have a concept of).
|
||||
*/
|
||||
typedef struct ELNK_XMIT_STAT {
|
||||
uint8_t uflow : 1; /* Underflow on transmit. */
|
||||
uint8_t coll : 1; /* Collision on transmit. */
|
||||
uint8_t coll16 : 1; /* 16 collisions on transmit. */
|
||||
uint8_t ready : 1; /* Ready for a new frame. */
|
||||
uint8_t undef : 4;
|
||||
uint8_t uflow : 1; /* Underflow on transmit. */
|
||||
uint8_t coll : 1; /* Collision on transmit. */
|
||||
uint8_t coll16 : 1; /* 16 collisions on transmit. */
|
||||
uint8_t ready : 1; /* Ready for a new frame. */
|
||||
uint8_t undef : 4;
|
||||
} EL_XMT_STAT;
|
||||
|
||||
/** Address match (adr_match) modes. */
|
||||
typedef enum {
|
||||
EL_ADRM_DISABLED = 0, /* Receiver disabled. */
|
||||
EL_ADRM_PROMISC = 1, /* Receive all addresses. */
|
||||
EL_ADRM_BCAST = 2, /* Receive station + broadcast. */
|
||||
EL_ADRM_MCAST = 3 /* Receive station + multicast. */
|
||||
EL_ADRM_DISABLED = 0, /* Receiver disabled. */
|
||||
EL_ADRM_PROMISC = 1, /* Receive all addresses. */
|
||||
EL_ADRM_BCAST = 2, /* Receive station + broadcast. */
|
||||
EL_ADRM_MCAST = 3 /* Receive station + multicast. */
|
||||
} EL_ADDR_MATCH;
|
||||
|
||||
/**
|
||||
* EtherLink Receive Command Register.
|
||||
*/
|
||||
typedef struct ELNK_RECV_CMD {
|
||||
uint8_t det_ofl : 1; /* Detect overflow errors. */
|
||||
uint8_t det_fcs : 1; /* Detect FCS errors. */
|
||||
uint8_t det_drbl : 1; /* Detect dribble error. */
|
||||
uint8_t det_runt : 1; /* Detect short frames. */
|
||||
uint8_t det_eof : 1; /* Detect EOF (frames without overflow). */
|
||||
uint8_t acpt_good : 1; /* Accept good frames. */
|
||||
uint8_t adr_match : 2; /* Address match mode. */
|
||||
uint8_t det_ofl : 1; /* Detect overflow errors. */
|
||||
uint8_t det_fcs : 1; /* Detect FCS errors. */
|
||||
uint8_t det_drbl : 1; /* Detect dribble error. */
|
||||
uint8_t det_runt : 1; /* Detect short frames. */
|
||||
uint8_t det_eof : 1; /* Detect EOF (frames without overflow). */
|
||||
uint8_t acpt_good : 1; /* Accept good frames. */
|
||||
uint8_t adr_match : 2; /* Address match mode. */
|
||||
} EL_RCV_CMD;
|
||||
|
||||
/**
|
||||
* EtherLink Receive Status Register.
|
||||
*/
|
||||
typedef struct ELNK_RECV_STAT {
|
||||
uint8_t oflow : 1; /* Overflow on receive. */
|
||||
uint8_t fcs : 1; /* FCS error. */
|
||||
uint8_t dribble : 1; /* Dribble error. */
|
||||
uint8_t runt : 1; /* Short frame. */
|
||||
uint8_t no_ovf : 1; /* Received packet w/o overflow. */
|
||||
uint8_t good : 1; /* Received good packet. */
|
||||
uint8_t undef : 1;
|
||||
uint8_t stale : 1; /* Stale receive status. */
|
||||
uint8_t oflow : 1; /* Overflow on receive. */
|
||||
uint8_t fcs : 1; /* FCS error. */
|
||||
uint8_t dribble : 1; /* Dribble error. */
|
||||
uint8_t runt : 1; /* Short frame. */
|
||||
uint8_t no_ovf : 1; /* Received packet w/o overflow. */
|
||||
uint8_t good : 1; /* Received good packet. */
|
||||
uint8_t undef : 1;
|
||||
uint8_t stale : 1; /* Stale receive status. */
|
||||
} EL_RCV_STAT;
|
||||
|
||||
/** Buffer control (buf_ctl) modes. */
|
||||
typedef enum {
|
||||
EL_BCTL_SYSTEM = 0, /* Host has buffer access. */
|
||||
EL_BCTL_XMT_RCV = 1, /* Transmit, then receive. */
|
||||
EL_BCTL_RECEIVE = 2, /* Receive. */
|
||||
EL_BCTL_LOOPBACK = 3 /* Loopback. */
|
||||
EL_BCTL_SYSTEM = 0, /* Host has buffer access. */
|
||||
EL_BCTL_XMT_RCV = 1, /* Transmit, then receive. */
|
||||
EL_BCTL_RECEIVE = 2, /* Receive. */
|
||||
EL_BCTL_LOOPBACK = 3 /* Loopback. */
|
||||
} EL_BUFFER_CONTROL;
|
||||
|
||||
/**
|
||||
* EtherLink Auxiliary Status Register.
|
||||
*/
|
||||
typedef struct ELNK_AUX_CMD {
|
||||
uint8_t ire : 1; /* Interrupt Request Enable. */
|
||||
uint8_t xmit_bf : 1; /* Xmit packets with bad FCS. */
|
||||
uint8_t buf_ctl : 2; /* Packet buffer control. */
|
||||
uint8_t unused : 1;
|
||||
uint8_t dma_req : 1; /* DMA request. */
|
||||
uint8_t ride : 1; /* Request Interrupt and DMA Enable. */
|
||||
uint8_t reset : 1; /* Card in reset while set. */
|
||||
uint8_t ire : 1; /* Interrupt Request Enable. */
|
||||
uint8_t xmit_bf : 1; /* Xmit packets with bad FCS. */
|
||||
uint8_t buf_ctl : 2; /* Packet buffer control. */
|
||||
uint8_t unused : 1;
|
||||
uint8_t dma_req : 1; /* DMA request. */
|
||||
uint8_t ride : 1; /* Request Interrupt and DMA Enable. */
|
||||
uint8_t reset : 1; /* Card in reset while set. */
|
||||
} EL_AUX_CMD;
|
||||
|
||||
/**
|
||||
* EtherLink Auxiliary Status Register.
|
||||
*/
|
||||
typedef struct ELNK_AUX_STAT {
|
||||
uint8_t recv_bsy : 1; /* Receive busy. */
|
||||
uint8_t xmit_bf : 1; /* Xmit packets with bad FCS. */
|
||||
uint8_t buf_ctl : 2; /* Packet buffer control. */
|
||||
uint8_t dma_done : 1; /* DMA done. */
|
||||
uint8_t dma_req : 1; /* DMA request. */
|
||||
uint8_t ride : 1; /* Request Interrupt and DMA Enable. */
|
||||
uint8_t xmit_bsy : 1; /* Transmit busy. */
|
||||
uint8_t recv_bsy : 1; /* Receive busy. */
|
||||
uint8_t xmit_bf : 1; /* Xmit packets with bad FCS. */
|
||||
uint8_t buf_ctl : 2; /* Packet buffer control. */
|
||||
uint8_t dma_done : 1; /* DMA done. */
|
||||
uint8_t dma_req : 1; /* DMA request. */
|
||||
uint8_t ride : 1; /* Request Interrupt and DMA Enable. */
|
||||
uint8_t xmit_bsy : 1; /* Transmit busy. */
|
||||
} EL_AUX_STAT;
|
||||
|
||||
/**
|
||||
* Internal interrupt status.
|
||||
*/
|
||||
typedef struct ELNK_INTR_STAT {
|
||||
uint8_t recv_intr : 1; /* Receive interrupt status. */
|
||||
uint8_t xmit_intr : 1; /* Transmit interrupt status. */
|
||||
uint8_t dma_intr : 1; /* DMA interrupt status. */
|
||||
uint8_t unused : 5;
|
||||
uint8_t recv_intr : 1; /* Receive interrupt status. */
|
||||
uint8_t xmit_intr : 1; /* Transmit interrupt status. */
|
||||
uint8_t dma_intr : 1; /* DMA interrupt status. */
|
||||
uint8_t unused : 5;
|
||||
} EL_INTR_STAT;
|
||||
|
||||
typedef struct {
|
||||
uint32_t base_address;
|
||||
int base_irq;
|
||||
uint32_t bios_addr;
|
||||
uint8_t maclocal[6]; /* configured MAC (local) address. */
|
||||
bool fISR; /* Internal interrupt flag. */
|
||||
int fDMA; /* Internal DMA active flag. */
|
||||
int fInReset; /* Internal in-reset flag. */
|
||||
uint8_t aPROM[8]; /* The PROM contents. Only 8 bytes addressable, R/O. */
|
||||
uint8_t aStationAddr[6]; /* The station address programmed by the guest, W/O. */
|
||||
uint16_t uGPBufPtr; /* General Purpose (GP) Buffer Pointer, R/W. */
|
||||
uint16_t uRCVBufPtr; /* Receive (RCV) Buffer Pointer, R/W. */
|
||||
uint32_t base_address;
|
||||
int base_irq;
|
||||
uint32_t bios_addr;
|
||||
uint8_t maclocal[6]; /* configured MAC (local) address. */
|
||||
bool fISR; /* Internal interrupt flag. */
|
||||
int fDMA; /* Internal DMA active flag. */
|
||||
int fInReset; /* Internal in-reset flag. */
|
||||
uint8_t aPROM[8]; /* The PROM contents. Only 8 bytes addressable, R/O. */
|
||||
uint8_t aStationAddr[6]; /* The station address programmed by the guest, W/O. */
|
||||
uint16_t uGPBufPtr; /* General Purpose (GP) Buffer Pointer, R/W. */
|
||||
uint16_t uRCVBufPtr; /* Receive (RCV) Buffer Pointer, R/W. */
|
||||
/** Transmit Command Register, W/O. */
|
||||
union {
|
||||
uint8_t XmitCmdReg;
|
||||
EL_XMT_CMD XmitCmd;
|
||||
uint8_t XmitCmdReg;
|
||||
EL_XMT_CMD XmitCmd;
|
||||
};
|
||||
/** Transmit Status Register, R/O. */
|
||||
union {
|
||||
uint8_t XmitStatReg;
|
||||
EL_XMT_STAT XmitStat;
|
||||
uint8_t XmitStatReg;
|
||||
EL_XMT_STAT XmitStat;
|
||||
};
|
||||
/** Receive Command Register, W/O. */
|
||||
union {
|
||||
uint8_t RcvCmdReg;
|
||||
EL_RCV_CMD RcvCmd;
|
||||
uint8_t RcvCmdReg;
|
||||
EL_RCV_CMD RcvCmd;
|
||||
};
|
||||
/** Receive Status Register, R/O. */
|
||||
union {
|
||||
uint8_t RcvStatReg;
|
||||
EL_RCV_STAT RcvStat;
|
||||
uint8_t RcvStatReg;
|
||||
EL_RCV_STAT RcvStat;
|
||||
};
|
||||
/** Auxiliary Command Register, W/O. */
|
||||
union {
|
||||
uint8_t AuxCmdReg;
|
||||
EL_AUX_CMD AuxCmd;
|
||||
uint8_t AuxCmdReg;
|
||||
EL_AUX_CMD AuxCmd;
|
||||
};
|
||||
/** Auxiliary Status Register, R/O. */
|
||||
union {
|
||||
uint8_t AuxStatReg;
|
||||
EL_AUX_STAT AuxStat;
|
||||
uint8_t AuxStatReg;
|
||||
EL_AUX_STAT AuxStat;
|
||||
};
|
||||
int fLinkUp; /* If set the link is currently up. */
|
||||
int fLinkTempDown; /* If set the link is temporarily down because of a saved state load. */
|
||||
uint16_t cLinkDownReported; /* Number of times we've reported the link down. */
|
||||
uint16_t cLinkRestorePostponed; /* Number of times we've postponed the link restore. */
|
||||
int fLinkUp; /* If set the link is currently up. */
|
||||
int fLinkTempDown; /* If set the link is temporarily down because of a saved state load. */
|
||||
uint16_t cLinkDownReported; /* Number of times we've reported the link down. */
|
||||
uint16_t cLinkRestorePostponed; /* Number of times we've postponed the link restore. */
|
||||
/* Internal interrupt state. */
|
||||
union {
|
||||
uint8_t IntrStateReg;
|
||||
EL_INTR_STAT IntrState;
|
||||
uint8_t IntrStateReg;
|
||||
EL_INTR_STAT IntrState;
|
||||
};
|
||||
uint32_t cMsLinkUpDelay; /* MS to wait before we enable the link. */
|
||||
int dma_channel;
|
||||
uint8_t abLoopBuf[ELNK_BUF_SIZE]; /* The loopback transmit buffer (avoid stack allocations). */
|
||||
uint8_t abRuntBuf[64]; /* The runt pad buffer (only really needs 60 bytes). */
|
||||
uint8_t abPacketBuf[ELNK_BUF_SIZE]; /* The packet buffer. */
|
||||
int dma_pos;
|
||||
pc_timer_t timer_restore;
|
||||
netcard_t *netcard;
|
||||
uint32_t cMsLinkUpDelay; /* MS to wait before we enable the link. */
|
||||
int dma_channel;
|
||||
uint8_t abLoopBuf[ELNK_BUF_SIZE]; /* The loopback transmit buffer (avoid stack allocations). */
|
||||
uint8_t abRuntBuf[64]; /* The runt pad buffer (only really needs 60 bytes). */
|
||||
uint8_t abPacketBuf[ELNK_BUF_SIZE]; /* The packet buffer. */
|
||||
int dma_pos;
|
||||
pc_timer_t timer_restore;
|
||||
netcard_t *netcard;
|
||||
} threec501_t;
|
||||
|
||||
#ifdef ENABLE_3COM501_LOG
|
||||
@@ -280,7 +279,7 @@ static void elnkR3HardReset(threec501_t *dev);
|
||||
#endif
|
||||
|
||||
#define ETHER_ADDR_LEN ETH_ALEN
|
||||
#define ETH_ALEN 6
|
||||
#define ETH_ALEN 6
|
||||
#pragma pack(1)
|
||||
struct ether_header /** @todo Use RTNETETHERHDR? */
|
||||
{
|
||||
@@ -325,8 +324,8 @@ static void
|
||||
elnkTempLinkDown(threec501_t *dev)
|
||||
{
|
||||
if (dev->fLinkUp) {
|
||||
dev->fLinkTempDown = 1;
|
||||
dev->cLinkDownReported = 0;
|
||||
dev->fLinkTempDown = 1;
|
||||
dev->cLinkDownReported = 0;
|
||||
dev->cLinkRestorePostponed = 0;
|
||||
timer_set_delay_u64(&dev->timer_restore, (dev->cMsLinkUpDelay * 1000) * TIMER_USEC);
|
||||
}
|
||||
@@ -341,7 +340,7 @@ elnkR3Reset(void *priv)
|
||||
threec501_t *dev = (threec501_t *) priv;
|
||||
|
||||
if (dev->fLinkTempDown) {
|
||||
dev->cLinkDownReported = 0x1000;
|
||||
dev->cLinkDownReported = 0x1000;
|
||||
dev->cLinkRestorePostponed = 0x1000;
|
||||
timer_disable(&dev->timer_restore);
|
||||
}
|
||||
@@ -367,15 +366,14 @@ elnkR3HardReset(threec501_t *dev)
|
||||
elnkSoftReset(dev);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if incoming frame matches the station address.
|
||||
*/
|
||||
static __inline int
|
||||
padr_match(threec501_t *dev, const uint8_t *buf)
|
||||
{
|
||||
struct ether_header *hdr = (struct ether_header *)buf;
|
||||
int result;
|
||||
struct ether_header *hdr = (struct ether_header *) buf;
|
||||
int result;
|
||||
|
||||
/* Checks own + broadcast as well as own + multicast. */
|
||||
result = (dev->RcvCmd.adr_match >= EL_ADRM_BCAST) && !memcmp(hdr->ether_dhost, dev->aStationAddr, 6);
|
||||
@@ -389,21 +387,20 @@ padr_match(threec501_t *dev, const uint8_t *buf)
|
||||
static __inline int
|
||||
padr_bcast(threec501_t *dev, const uint8_t *buf)
|
||||
{
|
||||
static uint8_t aBCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
struct ether_header *hdr = (struct ether_header *)buf;
|
||||
int result = (dev->RcvCmd.adr_match == EL_ADRM_BCAST) && !memcmp(hdr->ether_dhost, aBCAST, 6);
|
||||
static uint8_t aBCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
struct ether_header *hdr = (struct ether_header *) buf;
|
||||
int result = (dev->RcvCmd.adr_match == EL_ADRM_BCAST) && !memcmp(hdr->ether_dhost, aBCAST, 6);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if incoming frame is an accepted multicast frame.
|
||||
*/
|
||||
static __inline int
|
||||
padr_mcast(threec501_t *dev, const uint8_t *buf)
|
||||
{
|
||||
struct ether_header *hdr = (struct ether_header *)buf;
|
||||
int result = (dev->RcvCmd.adr_match == EL_ADRM_MCAST) && ETHER_IS_MULTICAST(hdr->ether_dhost);
|
||||
struct ether_header *hdr = (struct ether_header *) buf;
|
||||
int result = (dev->RcvCmd.adr_match == EL_ADRM_MCAST) && ETHER_IS_MULTICAST(hdr->ether_dhost);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -475,9 +472,9 @@ elnkSoftReset(threec501_t *dev)
|
||||
static int
|
||||
elnkReceiveLocked(void *priv, uint8_t *src, int size)
|
||||
{
|
||||
threec501_t *dev = (threec501_t *) priv;
|
||||
int is_padr = 0, is_bcast = 0, is_mcast = 0;
|
||||
bool fLoopback = dev->RcvCmd.adr_match == EL_BCTL_LOOPBACK;
|
||||
threec501_t *dev = (threec501_t *) priv;
|
||||
int is_padr = 0, is_bcast = 0, is_mcast = 0;
|
||||
bool fLoopback = dev->RcvCmd.adr_match == EL_BCTL_LOOPBACK;
|
||||
|
||||
union {
|
||||
uint8_t RcvStatNewReg;
|
||||
@@ -513,8 +510,8 @@ elnkReceiveLocked(void *priv, uint8_t *src, int size)
|
||||
* filter are always ignored.
|
||||
*/
|
||||
/// @todo cbToRecv must be 6 or more (complete address)
|
||||
if ((dev->RcvCmd.adr_match == EL_ADRM_PROMISC) /* promiscuous enabled */
|
||||
|| (is_padr = padr_match(dev, src))
|
||||
if ((dev->RcvCmd.adr_match == EL_ADRM_PROMISC) /* promiscuous enabled */
|
||||
|| (is_padr = padr_match(dev, src))
|
||||
|| (is_bcast = padr_bcast(dev, src))
|
||||
|| (is_mcast = padr_mcast(dev, src))) {
|
||||
uint8_t *dst = dev->abPacketBuf + dev->uRCVBufPtr;
|
||||
@@ -524,9 +521,9 @@ elnkReceiveLocked(void *priv, uint8_t *src, int size)
|
||||
#endif
|
||||
|
||||
/* Receive status is evaluated from scratch. The stale bit must remain set until we know better. */
|
||||
rcvstatnew.RcvStatNewReg = 0;
|
||||
rcvstatnew.RcvStatNewReg = 0;
|
||||
rcvstatnew.RcvStatNew.stale = 1;
|
||||
dev->RcvStatReg = 0x80;
|
||||
dev->RcvStatReg = 0x80;
|
||||
|
||||
/* Detect errors: Runts, overflow, and FCS errors.
|
||||
* NB: Dribble errors can not happen because we can only receive an
|
||||
@@ -549,7 +546,7 @@ elnkReceiveLocked(void *priv, uint8_t *src, int size)
|
||||
memset(dev->abRuntBuf, 0, sizeof(dev->abRuntBuf));
|
||||
memcpy(dev->abRuntBuf, src, size);
|
||||
size = 60;
|
||||
src = dev->abRuntBuf;
|
||||
src = dev->abRuntBuf;
|
||||
} else {
|
||||
#ifdef ENABLE_3COM501_LOG
|
||||
threec501_log("3Com501 runt, size=%d\n", size);
|
||||
@@ -582,7 +579,7 @@ elnkReceiveLocked(void *priv, uint8_t *src, int size)
|
||||
if (rcvstatnew.RcvStatNew.no_ovf && !rcvstatnew.RcvStatNew.fcs && !rcvstatnew.RcvStatNew.runt)
|
||||
rcvstatnew.RcvStatNew.good = 1;
|
||||
|
||||
uint16_t cbCopy = (uint16_t)MIN(ELNK_BUF_SIZE - dev->uRCVBufPtr, size);
|
||||
uint16_t cbCopy = (uint16_t) MIN(ELNK_BUF_SIZE - dev->uRCVBufPtr, size);
|
||||
|
||||
/* All packets that passed the address filter are copied to the buffer. */
|
||||
|
||||
@@ -604,15 +601,15 @@ elnkReceiveLocked(void *priv, uint8_t *src, int size)
|
||||
* NB: The precise receive logic is not very well described in the EtherLink
|
||||
* documentation. It was refined using the 3C501.EXE diagnostic utility.
|
||||
*/
|
||||
if ( (rcvstatnew.RcvStatNew.good && dev->RcvCmd.acpt_good)
|
||||
|| (rcvstatnew.RcvStatNew.no_ovf && dev->RcvCmd.det_eof)
|
||||
|| (rcvstatnew.RcvStatNew.runt && dev->RcvCmd.det_runt)
|
||||
if ((rcvstatnew.RcvStatNew.good && dev->RcvCmd.acpt_good)
|
||||
|| (rcvstatnew.RcvStatNew.no_ovf && dev->RcvCmd.det_eof)
|
||||
|| (rcvstatnew.RcvStatNew.runt && dev->RcvCmd.det_runt)
|
||||
|| (rcvstatnew.RcvStatNew.dribble && dev->RcvCmd.det_drbl)
|
||||
|| (rcvstatnew.RcvStatNew.fcs && dev->RcvCmd.det_fcs)
|
||||
|| (rcvstatnew.RcvStatNew.oflow && dev->RcvCmd.det_ofl)) {
|
||||
dev->AuxStat.recv_bsy = 0;
|
||||
dev->IntrState.recv_intr = 1;
|
||||
rcvstatnew.RcvStatNew.stale = 0; /* Prevents further receive until set again. */
|
||||
|| (rcvstatnew.RcvStatNew.fcs && dev->RcvCmd.det_fcs)
|
||||
|| (rcvstatnew.RcvStatNew.oflow && dev->RcvCmd.det_ofl)) {
|
||||
dev->AuxStat.recv_bsy = 0;
|
||||
dev->IntrState.recv_intr = 1;
|
||||
rcvstatnew.RcvStatNew.stale = 0; /* Prevents further receive until set again. */
|
||||
}
|
||||
|
||||
/* Finally update the receive status. */
|
||||
@@ -715,7 +712,7 @@ elnkAsyncTransmit(threec501_t *dev)
|
||||
|
||||
/* NB: The buffer control does *not* change to Receive and stays the way it was. */
|
||||
if (!fLoopback) {
|
||||
dev->AuxStat.recv_bsy = 1; /* Receive Busy now set until a packet is received. */
|
||||
dev->AuxStat.recv_bsy = 1; /* Receive Busy now set until a packet is received. */
|
||||
}
|
||||
} while (0); /* No loop, because there isn't ever more than one packet to transmit. */
|
||||
|
||||
@@ -725,14 +722,14 @@ elnkAsyncTransmit(threec501_t *dev)
|
||||
static void
|
||||
elnkCsrWrite(threec501_t *dev, uint8_t data)
|
||||
{
|
||||
bool fTransmit = false;
|
||||
bool fReceive = false;
|
||||
bool fDMAR;
|
||||
int mode;
|
||||
bool fTransmit = false;
|
||||
bool fReceive = false;
|
||||
bool fDMAR;
|
||||
int mode;
|
||||
|
||||
union {
|
||||
uint8_t reg;
|
||||
EL_AUX_CMD val;
|
||||
uint8_t reg;
|
||||
EL_AUX_CMD val;
|
||||
} auxcmd;
|
||||
|
||||
auxcmd.reg = data;
|
||||
@@ -759,7 +756,7 @@ elnkCsrWrite(threec501_t *dev, uint8_t data)
|
||||
#endif
|
||||
elnkSoftReset(dev);
|
||||
}
|
||||
dev->AuxCmd.reset = auxcmd.val.reset; /* Update the reset bit, if nothing else. */
|
||||
dev->AuxCmd.reset = auxcmd.val.reset; /* Update the reset bit, if nothing else. */
|
||||
}
|
||||
|
||||
/* If the card is in reset, stop right here. */
|
||||
@@ -788,14 +785,14 @@ elnkCsrWrite(threec501_t *dev, uint8_t data)
|
||||
}
|
||||
} else {
|
||||
while (dev->dma_pos < (ELNK_BUF_SIZE - ELNK_GP(dev))) {
|
||||
int dma_data = dma_channel_read(dev->dma_channel);
|
||||
int dma_data = dma_channel_read(dev->dma_channel);
|
||||
dev->abPacketBuf[ELNK_GP(dev) + dev->dma_pos] = dma_data & 0xff;
|
||||
dev->dma_pos++;
|
||||
}
|
||||
}
|
||||
dev->uGPBufPtr = (dev->uGPBufPtr + dev->dma_pos) & ELNK_GP_MASK;
|
||||
dma_set_drq(dev->dma_channel, 0);
|
||||
dev->dma_pos = 0;
|
||||
dev->dma_pos = 0;
|
||||
dev->IntrState.dma_intr = 1;
|
||||
dev->AuxStat.dma_done = 1;
|
||||
elnkUpdateIrq(dev);
|
||||
@@ -808,7 +805,7 @@ elnkCsrWrite(threec501_t *dev, uint8_t data)
|
||||
/* Interrupt enable changes. */
|
||||
if ((dev->AuxCmd.ire != auxcmd.val.ire) || (dev->AuxCmd.ride != auxcmd.val.ride)) {
|
||||
dev->AuxStat.ride = dev->AuxCmd.ride = auxcmd.val.ride;
|
||||
dev->AuxCmd.ire = auxcmd.val.ire; /* NB: IRE is not visible in the aux status register. */
|
||||
dev->AuxCmd.ire = auxcmd.val.ire; /* NB: IRE is not visible in the aux status register. */
|
||||
}
|
||||
|
||||
/* DMA Request changes. */
|
||||
@@ -824,15 +821,15 @@ elnkCsrWrite(threec501_t *dev, uint8_t data)
|
||||
/* Packet buffer control changes. */
|
||||
if (dev->AuxCmd.buf_ctl != auxcmd.val.buf_ctl) {
|
||||
#ifdef ENABLE_3COM501_LOG
|
||||
static const char *apszBuffCntrl[4] = { "System", "Xmit then Recv", "Receive", "Loopback" };
|
||||
static const char *apszBuffCntrl[4] = { "System", "Xmit then Recv", "Receive", "Loopback" };
|
||||
threec501_log("3Com501: Packet buffer control `%s' -> `%s'\n", apszBuffCntrl[dev->AuxCmd.buf_ctl], apszBuffCntrl[auxcmd.val.buf_ctl]);
|
||||
#endif
|
||||
if (auxcmd.val.buf_ctl == EL_BCTL_XMT_RCV) {
|
||||
/* Transmit, then receive. */
|
||||
fTransmit = true;
|
||||
fTransmit = true;
|
||||
dev->AuxStat.recv_bsy = 0;
|
||||
} else if (auxcmd.val.buf_ctl == EL_BCTL_SYSTEM) {
|
||||
dev->AuxStat.xmit_bsy = 1; /* Transmit Busy is set here and cleared once actual transmit completes. */
|
||||
dev->AuxStat.xmit_bsy = 1; /* Transmit Busy is set here and cleared once actual transmit completes. */
|
||||
dev->AuxStat.recv_bsy = 0;
|
||||
} else if (auxcmd.val.buf_ctl == EL_BCTL_RECEIVE) {
|
||||
/* Special case: If going from xmit-then-receive mode to receive mode, and we received
|
||||
@@ -845,8 +842,8 @@ elnkCsrWrite(threec501_t *dev, uint8_t data)
|
||||
/* For loopback, we go through the regular transmit and receive path. That may be an
|
||||
* overkill but the receive path is too complex for a special loopback-only case.
|
||||
*/
|
||||
fTransmit = true;
|
||||
dev->AuxStat.recv_bsy = 1; /* Receive Busy now set until a packet is received. */
|
||||
fTransmit = true;
|
||||
dev->AuxStat.recv_bsy = 1; /* Receive Busy now set until a packet is received. */
|
||||
}
|
||||
dev->AuxStat.buf_ctl = dev->AuxCmd.buf_ctl = auxcmd.val.buf_ctl;
|
||||
}
|
||||
@@ -863,7 +860,7 @@ elnkCsrWrite(threec501_t *dev, uint8_t data)
|
||||
if (fTransmit)
|
||||
elnkAsyncTransmit(dev);
|
||||
else if (fReceive) {
|
||||
dev->AuxStat.recv_bsy = 1; /* Receive Busy now set until a packet is received. */
|
||||
dev->AuxStat.recv_bsy = 1; /* Receive Busy now set until a packet is received. */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -874,52 +871,52 @@ threec501_read(uint16_t addr, void *priv)
|
||||
uint8_t retval = 0xff;
|
||||
|
||||
switch (addr & 0x0f) {
|
||||
case 0x00: /* Receive status register aliases. The SEEQ 8001 */
|
||||
case 0x02: /* EDLC clearly only decodes one bit for reads. */
|
||||
case 0x00: /* Receive status register aliases. The SEEQ 8001 */
|
||||
case 0x02: /* EDLC clearly only decodes one bit for reads. */
|
||||
case 0x04:
|
||||
case 0x06: /* Receive status register. */
|
||||
retval = dev->RcvStatReg;
|
||||
dev->RcvStat.stale = 1; /* Allows further reception. */
|
||||
case 0x06: /* Receive status register. */
|
||||
retval = dev->RcvStatReg;
|
||||
dev->RcvStat.stale = 1; /* Allows further reception. */
|
||||
dev->IntrState.recv_intr = 0; /* Reading clears receive interrupt. */
|
||||
elnkUpdateIrq(dev);
|
||||
break;
|
||||
|
||||
case 0x01: /* Transmit status register aliases. */
|
||||
case 0x01: /* Transmit status register aliases. */
|
||||
case 0x03:
|
||||
case 0x05:
|
||||
case 0x07: /* Transmit status register. */
|
||||
retval = dev->XmitStatReg;
|
||||
case 0x07: /* Transmit status register. */
|
||||
retval = dev->XmitStatReg;
|
||||
dev->IntrState.xmit_intr = 0; /* Reading clears transmit interrupt. */
|
||||
elnkUpdateIrq(dev);
|
||||
break;
|
||||
|
||||
case 0x08: /* GP Buffer pointer LSB. */
|
||||
case 0x08: /* GP Buffer pointer LSB. */
|
||||
retval = (dev->uGPBufPtr & 0xff);
|
||||
break;
|
||||
case 0x09: /* GP Buffer pointer MSB. */
|
||||
case 0x09: /* GP Buffer pointer MSB. */
|
||||
retval = (dev->uGPBufPtr >> 8);
|
||||
break;
|
||||
|
||||
case 0x0a: /* RCV Buffer pointer LSB. */
|
||||
case 0x0a: /* RCV Buffer pointer LSB. */
|
||||
retval = (dev->uRCVBufPtr & 0xff);
|
||||
break;
|
||||
case 0x0b: /* RCV Buffer pointer MSB. */
|
||||
case 0x0b: /* RCV Buffer pointer MSB. */
|
||||
retval = (dev->uRCVBufPtr >> 8);
|
||||
break;
|
||||
|
||||
case 0x0c: /* Ethernet address PROM window. */
|
||||
case 0x0d: /* Alias. */
|
||||
case 0x0c: /* Ethernet address PROM window. */
|
||||
case 0x0d: /* Alias. */
|
||||
/* Reads use low 3 bits of GP buffer pointer, no auto-increment. */
|
||||
retval = dev->aPROM[dev->uGPBufPtr & 7];
|
||||
break;
|
||||
|
||||
case 0x0e: /* Auxiliary status register. */
|
||||
case 0x0e: /* Auxiliary status register. */
|
||||
retval = dev->AuxStatReg;
|
||||
break;
|
||||
|
||||
case 0x0f: /* Buffer window. */
|
||||
case 0x0f: /* Buffer window. */
|
||||
/* Reads use low 11 bits of GP buffer pointer, auto-increment. */
|
||||
retval = dev->abPacketBuf[ELNK_GP(dev)];
|
||||
retval = dev->abPacketBuf[ELNK_GP(dev)];
|
||||
dev->uGPBufPtr = (dev->uGPBufPtr + 1) & ELNK_GP_MASK;
|
||||
break;
|
||||
}
|
||||
@@ -973,40 +970,40 @@ threec501_write(uint16_t addr, uint8_t value, void *priv)
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x08: /* GP Buffer pointer LSB. */
|
||||
case 0x08: /* GP Buffer pointer LSB. */
|
||||
dev->uGPBufPtr = (dev->uGPBufPtr & 0xff00) | value;
|
||||
break;
|
||||
case 0x09: /* GP Buffer pointer MSB. */
|
||||
case 0x09: /* GP Buffer pointer MSB. */
|
||||
dev->uGPBufPtr = (dev->uGPBufPtr & 0x00ff) | (value << 8);
|
||||
break;
|
||||
|
||||
case 0x0a: /* RCV Buffer pointer clear. */
|
||||
case 0x0a: /* RCV Buffer pointer clear. */
|
||||
dev->uRCVBufPtr = 0;
|
||||
#ifdef ENABLE_3COM501_LOG
|
||||
threec501_log("3Com501: RCV Buffer Pointer cleared (%02X)\n", value);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x0b: /* RCV buffer pointer MSB. */
|
||||
case 0x0c: /* Ethernet address PROM window. */
|
||||
case 0x0d: /* Undocumented. */
|
||||
case 0x0b: /* RCV buffer pointer MSB. */
|
||||
case 0x0c: /* Ethernet address PROM window. */
|
||||
case 0x0d: /* Undocumented. */
|
||||
#ifdef ENABLE_3COM501_LOG
|
||||
threec501_log("3Com501: Writing read-only register %02X!\n", reg);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x0e: /* Auxiliary Command (CSR). */
|
||||
case 0x0e: /* Auxiliary Command (CSR). */
|
||||
elnkCsrWrite(dev, value);
|
||||
break;
|
||||
|
||||
case 0x0f: /* Buffer window. */
|
||||
case 0x0f: /* Buffer window. */
|
||||
/* Writes use low 11 bits of GP buffer pointer, auto-increment. */
|
||||
if (dev->AuxCmd.buf_ctl != EL_BCTL_SYSTEM) {
|
||||
/// @todo Does this still increment GPBufPtr?
|
||||
break;
|
||||
}
|
||||
dev->abPacketBuf[ELNK_GP(dev)] = value;
|
||||
dev->uGPBufPtr = (dev->uGPBufPtr + 1) & ELNK_GP_MASK;
|
||||
dev->uGPBufPtr = (dev->uGPBufPtr + 1) & ELNK_GP_MASK;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1042,12 +1039,12 @@ elnkSetLinkState(void *priv, uint32_t link_state)
|
||||
if (dev->fLinkUp != link_up) {
|
||||
dev->fLinkUp = link_up;
|
||||
if (link_up) {
|
||||
dev->fLinkTempDown = 1;
|
||||
dev->cLinkDownReported = 0;
|
||||
dev->fLinkTempDown = 1;
|
||||
dev->cLinkDownReported = 0;
|
||||
dev->cLinkRestorePostponed = 0;
|
||||
timer_set_delay_u64(&dev->timer_restore, (dev->cMsLinkUpDelay * 1000) * TIMER_USEC);
|
||||
} else {
|
||||
dev->cLinkDownReported = 0;
|
||||
dev->cLinkDownReported = 0;
|
||||
dev->cLinkRestorePostponed = 0;
|
||||
}
|
||||
}
|
||||
@@ -1060,8 +1057,7 @@ elnkR3TimerRestore(void *priv)
|
||||
{
|
||||
threec501_t *dev = (threec501_t *) priv;
|
||||
|
||||
if ((dev->cLinkDownReported <= ELNK_MAX_LINKDOWN_REPORTED) &&
|
||||
(dev->cLinkRestorePostponed <= ELNK_MAX_LINKRST_POSTPONED)) {
|
||||
if ((dev->cLinkDownReported <= ELNK_MAX_LINKDOWN_REPORTED) && (dev->cLinkRestorePostponed <= ELNK_MAX_LINKRST_POSTPONED)) {
|
||||
timer_advance_u64(&dev->timer_restore, 1500000 * TIMER_USEC);
|
||||
dev->cLinkRestorePostponed++;
|
||||
} else {
|
||||
@@ -1117,7 +1113,7 @@ threec501_nic_init(const device_t *info)
|
||||
|
||||
/* Initialize the PROM */
|
||||
memcpy(dev->aPROM, dev->maclocal, sizeof(dev->maclocal));
|
||||
dev->aPROM[6] = dev->aPROM[7] = 0; /* The two padding bytes. */
|
||||
dev->aPROM[6] = dev->aPROM[7] = 0; /* The two padding bytes. */
|
||||
|
||||
#ifdef ENABLE_3COM501_LOG
|
||||
threec501_log("I/O=%04x, IRQ=%d, DMA=%d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
@@ -1210,15 +1206,15 @@ static const device_config_t threec501_config[] = {
|
||||
};
|
||||
|
||||
const device_t threec501_device = {
|
||||
.name = "3Com EtherLink (3c500/3c501)",
|
||||
.name = "3Com EtherLink (3c500/3c501)",
|
||||
.internal_name = "3c501",
|
||||
.flags = DEVICE_ISA,
|
||||
.local = 0,
|
||||
.init = threec501_nic_init,
|
||||
.close = threec501_nic_close,
|
||||
.reset = elnkR3Reset,
|
||||
.flags = DEVICE_ISA,
|
||||
.local = 0,
|
||||
.init = threec501_nic_init,
|
||||
.close = threec501_nic_close,
|
||||
.reset = elnkR3Reset,
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = threec501_config
|
||||
.force_redraw = NULL,
|
||||
.config = threec501_config
|
||||
};
|
||||
|
||||
157
src/pci_dummy.c
157
src/pci_dummy.c
@@ -32,7 +32,7 @@ static uint8_t
|
||||
pci_dummy_read(uint16_t Port, void *p)
|
||||
{
|
||||
pci_dummy_t *dev = (pci_dummy_t *) p;
|
||||
uint8_t ret = 0xff;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
switch (Port & 0x20) {
|
||||
case 0x00:
|
||||
@@ -120,51 +120,57 @@ static uint8_t
|
||||
pci_dummy_pci_read(int func, int addr, void *priv)
|
||||
{
|
||||
pci_dummy_t *dev = (pci_dummy_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
if (func == 0x00) switch (addr) {
|
||||
case 0x00: case 0x2c:
|
||||
ret = 0x1a;
|
||||
break;
|
||||
case 0x01: case 0x2d:
|
||||
ret = 0x07;
|
||||
break;
|
||||
if (func == 0x00)
|
||||
switch (addr) {
|
||||
case 0x00:
|
||||
case 0x2c:
|
||||
ret = 0x1a;
|
||||
break;
|
||||
case 0x01:
|
||||
case 0x2d:
|
||||
ret = 0x07;
|
||||
break;
|
||||
|
||||
case 0x02: case 0x2e:
|
||||
ret = 0x0b;
|
||||
break;
|
||||
case 0x03: case 0x2f:
|
||||
ret = 0xab;
|
||||
break;
|
||||
case 0x02:
|
||||
case 0x2e:
|
||||
ret = 0x0b;
|
||||
break;
|
||||
case 0x03:
|
||||
case 0x2f:
|
||||
ret = 0xab;
|
||||
break;
|
||||
|
||||
case 0x04: /* PCI_COMMAND_LO */
|
||||
case 0x05: /* PCI_COMMAND_HI */
|
||||
case 0x06: /* PCI_STATUS_LO */
|
||||
case 0x07: /* PCI_STATUS_HI */
|
||||
case 0x0a: case 0x0b:
|
||||
case 0x3c: /* PCI_ILR */
|
||||
ret = dev->pci_regs[addr];
|
||||
break;
|
||||
case 0x04: /* PCI_COMMAND_LO */
|
||||
case 0x05: /* PCI_COMMAND_HI */
|
||||
case 0x06: /* PCI_STATUS_LO */
|
||||
case 0x07: /* PCI_STATUS_HI */
|
||||
case 0x0a:
|
||||
case 0x0b:
|
||||
case 0x3c: /* PCI_ILR */
|
||||
ret = dev->pci_regs[addr];
|
||||
break;
|
||||
|
||||
case 0x08: /* Techncially, revision, but we return the card (slot) here. */
|
||||
ret = dev->card;
|
||||
break;
|
||||
case 0x08: /* Techncially, revision, but we return the card (slot) here. */
|
||||
ret = dev->card;
|
||||
break;
|
||||
|
||||
case 0x10: /* PCI_BAR 7:5 */
|
||||
ret = (dev->pci_bar[0].addr_regs[0] & 0xe0) | 0x01;
|
||||
break;
|
||||
case 0x11: /* PCI_BAR 15:8 */
|
||||
ret = dev->pci_bar[0].addr_regs[1];
|
||||
break;
|
||||
case 0x10: /* PCI_BAR 7:5 */
|
||||
ret = (dev->pci_bar[0].addr_regs[0] & 0xe0) | 0x01;
|
||||
break;
|
||||
case 0x11: /* PCI_BAR 15:8 */
|
||||
ret = dev->pci_bar[0].addr_regs[1];
|
||||
break;
|
||||
|
||||
case 0x3d: /* PCI_IPR */
|
||||
ret = PCI_INTA;
|
||||
break;
|
||||
case 0x3d: /* PCI_IPR */
|
||||
ret = PCI_INTA;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = 0x00;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = 0x00;
|
||||
break;
|
||||
}
|
||||
|
||||
// pclog("AB0B:071A: PCI_Read(%d, %04X) = %02X\n", func, addr, ret);
|
||||
|
||||
@@ -175,50 +181,51 @@ static void
|
||||
pci_dummy_pci_write(int func, int addr, uint8_t val, void *priv)
|
||||
{
|
||||
pci_dummy_t *dev = (pci_dummy_t *) priv;
|
||||
uint8_t valxor;
|
||||
uint8_t valxor;
|
||||
|
||||
// pclog("AB0B:071A: PCI_Write(%d, %04X, %02X)\n", func, addr, val);
|
||||
|
||||
if (func == 0x00) switch (addr) {
|
||||
case 0x04: /* PCI_COMMAND_LO */
|
||||
valxor = (val & 0x03) ^ dev->pci_regs[addr];
|
||||
if (valxor & PCI_COMMAND_IO) {
|
||||
if (func == 0x00)
|
||||
switch (addr) {
|
||||
case 0x04: /* PCI_COMMAND_LO */
|
||||
valxor = (val & 0x03) ^ dev->pci_regs[addr];
|
||||
if (valxor & PCI_COMMAND_IO) {
|
||||
pci_dummy_io_remove(dev);
|
||||
if ((dev->pci_bar[0].addr != 0) && (val & PCI_COMMAND_IO))
|
||||
pci_dummy_io_set(dev);
|
||||
}
|
||||
dev->pci_regs[addr] = val & 0x03;
|
||||
break;
|
||||
|
||||
case 0x10: /* PCI_BAR */
|
||||
val &= 0xe0; /* 0xe0 acc to RTL DS */
|
||||
/*FALLTHROUGH*/
|
||||
|
||||
case 0x11: /* PCI_BAR */
|
||||
/* Remove old I/O. */
|
||||
pci_dummy_io_remove(dev);
|
||||
if ((dev->pci_bar[0].addr != 0) && (val & PCI_COMMAND_IO))
|
||||
pci_dummy_io_set(dev);
|
||||
}
|
||||
dev->pci_regs[addr] = val & 0x03;
|
||||
break;
|
||||
|
||||
case 0x10: /* PCI_BAR */
|
||||
val &= 0xe0; /* 0xe0 acc to RTL DS */
|
||||
/*FALLTHROUGH*/
|
||||
/* Set new I/O as per PCI request. */
|
||||
dev->pci_bar[0].addr_regs[addr & 3] = val;
|
||||
|
||||
case 0x11: /* PCI_BAR */
|
||||
/* Remove old I/O. */
|
||||
pci_dummy_io_remove(dev);
|
||||
/* Then let's calculate the new I/O base. */
|
||||
dev->pci_bar[0].addr &= 0xffe0;
|
||||
|
||||
/* Set new I/O as per PCI request. */
|
||||
dev->pci_bar[0].addr_regs[addr & 3] = val;
|
||||
/* Log the new base. */
|
||||
// pclog("AB0B:071A: PCI: new I/O base is %04X\n", dev->pci_bar[0].addr);
|
||||
|
||||
/* Then let's calculate the new I/O base. */
|
||||
dev->pci_bar[0].addr &= 0xffe0;
|
||||
/* We're done, so get out of the here. */
|
||||
if (dev->pci_regs[4] & PCI_COMMAND_IO) {
|
||||
if ((dev->pci_bar[0].addr) != 0)
|
||||
pci_dummy_io_set(dev);
|
||||
}
|
||||
break;
|
||||
|
||||
/* Log the new base. */
|
||||
// pclog("AB0B:071A: PCI: new I/O base is %04X\n", dev->pci_bar[0].addr);
|
||||
|
||||
/* We're done, so get out of the here. */
|
||||
if (dev->pci_regs[4] & PCI_COMMAND_IO) {
|
||||
if ((dev->pci_bar[0].addr) != 0)
|
||||
pci_dummy_io_set(dev);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3c: /* PCI_ILR */
|
||||
pclog("AB0B:071A Device %02X: IRQ now: %i\n", dev->card, val);
|
||||
dev->pci_regs[addr] = val;
|
||||
return;
|
||||
}
|
||||
case 0x3c: /* PCI_ILR */
|
||||
pclog("AB0B:071A Device %02X: IRQ now: %i\n", dev->card, val);
|
||||
dev->pci_regs[addr] = val;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -275,7 +282,7 @@ pci_dummy_init(int min_slot, int max_slot, int nb_slot, int sb_slot)
|
||||
|
||||
for (i = min_slot; i <= max_slot; i++) {
|
||||
if ((i != nb_slot) && (i != sb_slot)) {
|
||||
pci_register_slot(i, PCI_CARD_NORMAL, 1, 3, 2, 4);
|
||||
pci_register_slot(i, PCI_CARD_NORMAL, 1, 3, 2, 4);
|
||||
device_add_inst(&pci_dummy_device, j);
|
||||
j++;
|
||||
}
|
||||
|
||||
76
src/pic.c
76
src/pic.c
@@ -51,7 +51,8 @@ static pc_timer_t pic_timer;
|
||||
|
||||
static int shadow = 0, elcr_enabled = 0,
|
||||
tmr_inited = 0, latched = 0,
|
||||
pic_pci = 0;
|
||||
pic_pci = 0, kbd_latch = 0,
|
||||
mouse_latch = 0;
|
||||
|
||||
static uint16_t smi_irq_mask = 0x0000,
|
||||
smi_irq_status = 0x0000;
|
||||
@@ -284,6 +285,12 @@ pic_set_shadow(int sh)
|
||||
shadow = sh;
|
||||
}
|
||||
|
||||
int
|
||||
pic_get_pci_flag(void)
|
||||
{
|
||||
return pic_pci;
|
||||
}
|
||||
|
||||
void
|
||||
pic_set_pci_flag(int pci)
|
||||
{
|
||||
@@ -383,6 +390,23 @@ pic_command(pic_t *dev)
|
||||
dev->auto_eoi_rotate = !!(dev->ocw2 & 0x80);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
pic_latch_read(uint16_t addr, void *priv)
|
||||
{
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
pic_log("pic_latch_read(%i, %i): %02X%02X\n", kbd_latch, mouse_latch, pic2.lines & 0x10, pic.lines & 0x02);
|
||||
|
||||
if (kbd_latch && (pic.lines & 0x02))
|
||||
picintc(0x0002);
|
||||
|
||||
if (mouse_latch && (pic2.lines & 0x10))
|
||||
picintc(0x1000);
|
||||
|
||||
/* Return FF - we just lower IRQ 1 and IRQ 12. */
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
pic_read(uint16_t addr, void *priv)
|
||||
{
|
||||
@@ -514,10 +538,47 @@ pic_set_pci(void)
|
||||
}
|
||||
|
||||
void
|
||||
pic_init(void)
|
||||
pic_kbd_latch(int enable)
|
||||
{
|
||||
pic_log("PIC keyboard latch now %sabled\n", enable ? "en" : "dis");
|
||||
|
||||
if (!!(enable | mouse_latch) != !!(kbd_latch | mouse_latch))
|
||||
io_handler(!!(enable | mouse_latch), 0x0060, 0x0001, pic_latch_read, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
kbd_latch = !!enable;
|
||||
|
||||
if (!enable)
|
||||
picintc(0x0002);
|
||||
}
|
||||
|
||||
void
|
||||
pic_mouse_latch(int enable)
|
||||
{
|
||||
pic_log("PIC mouse latch now %sabled\n", enable ? "en" : "dis");
|
||||
|
||||
if (!!(kbd_latch | enable) != !!(kbd_latch | mouse_latch))
|
||||
io_handler(!!(kbd_latch | enable), 0x0060, 0x0001, pic_latch_read, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
mouse_latch = !!enable;
|
||||
|
||||
if (!enable)
|
||||
picintc(0x1000);
|
||||
}
|
||||
|
||||
static void
|
||||
pic_reset_hard(void)
|
||||
{
|
||||
pic_reset();
|
||||
|
||||
pic_kbd_latch(0x00);
|
||||
pic_mouse_latch(0x00);
|
||||
}
|
||||
|
||||
void
|
||||
pic_init(void)
|
||||
{
|
||||
pic_reset_hard();
|
||||
|
||||
shadow = 0;
|
||||
io_sethandler(0x0020, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic);
|
||||
}
|
||||
@@ -525,7 +586,7 @@ pic_init(void)
|
||||
void
|
||||
pic_init_pcjr(void)
|
||||
{
|
||||
pic_reset();
|
||||
pic_reset_hard();
|
||||
|
||||
shadow = 0;
|
||||
io_sethandler(0x0020, 0x0008, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic);
|
||||
@@ -582,6 +643,10 @@ picint_common(uint16_t num, int level, int set)
|
||||
if (level)
|
||||
pic2.lines |= (num >> 8);
|
||||
|
||||
/* Latch IRQ 12 if the mouse latch is enabled. */
|
||||
if (mouse_latch && (num & 0x1000))
|
||||
pic2.lines |= 0x10;
|
||||
|
||||
pic2.irr |= (num >> 8);
|
||||
}
|
||||
|
||||
@@ -589,6 +654,9 @@ picint_common(uint16_t num, int level, int set)
|
||||
if (level)
|
||||
pic.lines |= (num & 0x00ff);
|
||||
|
||||
if (kbd_latch && (num & 0x0002))
|
||||
pic.lines |= 0x02;
|
||||
|
||||
pic.irr |= (num & 0x00ff);
|
||||
}
|
||||
} else {
|
||||
@@ -596,11 +664,13 @@ picint_common(uint16_t num, int level, int set)
|
||||
|
||||
if (num & 0xff00) {
|
||||
pic2.lines &= ~(num >> 8);
|
||||
|
||||
pic2.irr &= ~(num >> 8);
|
||||
}
|
||||
|
||||
if (num & 0x00ff) {
|
||||
pic.lines &= ~(num & 0x00ff);
|
||||
|
||||
pic.irr &= ~(num & 0x00ff);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,3 +14,10 @@
|
||||
#
|
||||
|
||||
add_library(print OBJECT png.c prt_cpmap.c prt_escp.c prt_text.c prt_ps.c)
|
||||
|
||||
if(APPLE)
|
||||
find_library(GHOSTSCRIPT_LIB gs)
|
||||
if (NOT GHOSTSCRIPT_LIB)
|
||||
message(WARNING "Could not find ghostscript. The library will not be bundled and any related features will not work.")
|
||||
endif()
|
||||
endif ()
|
||||
@@ -299,7 +299,7 @@ endif()
|
||||
|
||||
# loads a macro to install Qt5 plugins on macOS
|
||||
# based on https://stackoverflow.com/questions/35612687/cmake-macos-x-bundle-with-bundleutiliies-for-qt-application
|
||||
macro(install_qt5_plugin _qt_plugin_name _qt_plugins_var _prefix)
|
||||
macro(install_qt5_plugin _qt_plugin_name _runtime_plugins_var _prefix)
|
||||
get_target_property(_qt_plugin_path "${_qt_plugin_name}" LOCATION)
|
||||
if(EXISTS "${_qt_plugin_path}")
|
||||
get_filename_component(_qt_plugin_file "${_qt_plugin_path}" NAME)
|
||||
@@ -307,7 +307,7 @@ macro(install_qt5_plugin _qt_plugin_name _qt_plugins_var _prefix)
|
||||
get_filename_component(_qt_plugin_type "${_qt_plugin_type}" NAME)
|
||||
set(_qt_plugin_dest "${_prefix}/PlugIns/${_qt_plugin_type}")
|
||||
install(FILES "${_qt_plugin_path}" DESTINATION "${_qt_plugin_dest}")
|
||||
list(APPEND ${_qt_plugins_var} "\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/${_qt_plugin_dest}/${_qt_plugin_file}")
|
||||
list(APPEND ${_runtime_plugins_var} "\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/${_qt_plugin_dest}/${_qt_plugin_file}")
|
||||
else()
|
||||
message(FATAL_ERROR "QT plugin ${_qt_plugin_name} not found")
|
||||
endif()
|
||||
@@ -320,10 +320,25 @@ if (APPLE AND CMAKE_MACOSX_BUNDLE)
|
||||
set(INSTALL_LIB_DIR "${prefix}/Frameworks")
|
||||
|
||||
# using the install_qt5_plugin to add Qt plugins into the macOS app bundle
|
||||
install_qt5_plugin("Qt${QT_MAJOR}::QCocoaIntegrationPlugin" QT_PLUGINS ${prefix})
|
||||
install_qt5_plugin("Qt${QT_MAJOR}::QMacStylePlugin" QT_PLUGINS ${prefix})
|
||||
install_qt5_plugin("Qt${QT_MAJOR}::QICOPlugin" QT_PLUGINS ${prefix})
|
||||
install_qt5_plugin("Qt${QT_MAJOR}::QICNSPlugin" QT_PLUGINS ${prefix})
|
||||
install_qt5_plugin("Qt${QT_MAJOR}::QCocoaIntegrationPlugin" RUNTIME_PLUGINS ${prefix})
|
||||
install_qt5_plugin("Qt${QT_MAJOR}::QMacStylePlugin" RUNTIME_PLUGINS ${prefix})
|
||||
install_qt5_plugin("Qt${QT_MAJOR}::QICOPlugin" RUNTIME_PLUGINS ${prefix})
|
||||
install_qt5_plugin("Qt${QT_MAJOR}::QICNSPlugin" RUNTIME_PLUGINS ${prefix})
|
||||
|
||||
# Install libraries that are loaded at runtime and not linked
|
||||
if (GHOSTSCRIPT_LIB)
|
||||
set(GS_LIBRARY_NAME "libgs.dylib")
|
||||
file(REAL_PATH ${GHOSTSCRIPT_LIB} GS_LIB_RESOLVED)
|
||||
install(FILES ${GS_LIB_RESOLVED} DESTINATION ${INSTALL_LIB_DIR} RENAME ${GS_LIBRARY_NAME})
|
||||
list(APPEND RUNTIME_PLUGINS "\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/${INSTALL_LIB_DIR}/${GS_LIBRARY_NAME}")
|
||||
endif ()
|
||||
|
||||
if (FLUIDSYNTH_LIB)
|
||||
set(FLUIDSYNTH_LIBRARY_NAME "libfluidsynth.dylib")
|
||||
file(REAL_PATH ${FLUIDSYNTH_LIB} FLUIDSYNTH_LIB_RESOLVED)
|
||||
install(FILES ${FLUIDSYNTH_LIB_RESOLVED} DESTINATION ${INSTALL_LIB_DIR} RENAME ${FLUIDSYNTH_LIBRARY_NAME})
|
||||
list(APPEND RUNTIME_PLUGINS "\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/${INSTALL_LIB_DIR}/${FLUIDSYNTH_LIBRARY_NAME}")
|
||||
endif ()
|
||||
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
|
||||
"[Paths]\nPlugins = PlugIns\n")
|
||||
@@ -345,7 +360,7 @@ if (APPLE AND CMAKE_MACOSX_BUNDLE)
|
||||
install(CODE "
|
||||
include(BundleUtilities)
|
||||
get_filename_component(CMAKE_INSTALL_PREFIX_ABSOLUTE \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX} ABSOLUTE)
|
||||
fixup_bundle(\"\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/86Box.app\" \"${QT_PLUGINS}\" \"${DIRS}\")
|
||||
fixup_bundle(\"\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/86Box.app\" \"${RUNTIME_PLUGINS}\" \"${DIRS}\")
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath \"@executable_path/../Frameworks/\"
|
||||
\"\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/${INSTALL_RUNTIME_DIR}/86Box\")
|
||||
@@ -365,7 +380,7 @@ endif()
|
||||
if (UNIX AND NOT APPLE AND NOT HAIKU)
|
||||
find_package(X11 REQUIRED)
|
||||
target_link_libraries(ui PRIVATE X11::X11 X11::Xi)
|
||||
target_sources(ui PRIVATE xinput2_mouse.cpp)
|
||||
target_sources(ui PRIVATE evdev_keyboard.cpp xinput2_mouse.cpp)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(LIBEVDEV IMPORTED_TARGET libevdev)
|
||||
if (LIBEVDEV_FOUND)
|
||||
@@ -373,6 +388,22 @@ if (UNIX AND NOT APPLE AND NOT HAIKU)
|
||||
target_link_libraries(ui PUBLIC PkgConfig::LIBEVDEV)
|
||||
target_sources(ui PRIVATE evdev_mouse.cpp)
|
||||
endif()
|
||||
pkg_check_modules(XKBCOMMON IMPORTED_TARGET xkbcommon)
|
||||
if (XKBCOMMON_FOUND)
|
||||
target_compile_definitions(ui PRIVATE XKBCOMMON)
|
||||
target_link_libraries(ui PUBLIC PkgConfig::XKBCOMMON)
|
||||
target_sources(ui PRIVATE xkbcommon_keyboard.cpp)
|
||||
|
||||
if (X11_xcb_FOUND)
|
||||
pkg_check_modules(XKBCOMMON_X11 IMPORTED_TARGET xkbcommon-x11)
|
||||
if (XKBCOMMON_X11_FOUND)
|
||||
target_compile_definitions(ui PRIVATE XKBCOMMON_X11)
|
||||
target_link_libraries(ui PRIVATE X11::xcb PUBLIC PkgConfig::XKBCOMMON_X11)
|
||||
target_sources(ui PRIVATE xkbcommon_x11_keyboard.cpp)
|
||||
set(QT5_PRIVATE_HEADERS ON)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(ECM NO_MODULE)
|
||||
if (ECM_FOUND)
|
||||
@@ -387,10 +418,22 @@ if (UNIX AND NOT APPLE AND NOT HAIKU)
|
||||
ecm_add_wayland_client_protocol(WL_SOURCE_VAR PROTOCOL ${CMAKE_SOURCE_DIR}/wl_protocols/pointer-constraints-unstable-v1.xml BASENAME pointer-constraints-unstable-v1)
|
||||
target_include_directories(ui PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${Qt${QT_MAJOR}Gui_PRIVATE_INCLUDE_DIRS})
|
||||
target_sources(ui PRIVATE ${WL_SOURCE_VAR} wl_mouse.cpp)
|
||||
if (XKBCOMMON_FOUND)
|
||||
target_sources(ui PRIVATE xkbcommon_wl_keyboard.cpp)
|
||||
endif()
|
||||
target_compile_definitions(ui PRIVATE WAYLAND)
|
||||
set(QT5_PRIVATE_HEADERS ON)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Add private headers for Qt5 if required.
|
||||
if (NOT USE_QT6 AND DEFINED QT5_PRIVATE_HEADERS)
|
||||
find_package(Qt${QT_MAJOR}Gui)
|
||||
if (Qt${QT_MAJOR}Gui_FOUND)
|
||||
include_directories(${Qt${QT_MAJOR}Gui_PRIVATE_INCLUDE_DIRS})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
set(QM_FILES)
|
||||
file(GLOB po_files "${CMAKE_CURRENT_SOURCE_DIR}/languages/*.po")
|
||||
|
||||
112
src/qt/be_keyboard.hpp
Normal file
112
src/qt/be_keyboard.hpp
Normal file
@@ -0,0 +1,112 @@
|
||||
static std::unordered_map<uint8_t, uint16_t> be_keycodes = {
|
||||
{B_F1_KEY, 0x3b},
|
||||
{B_F2_KEY, 0x3c},
|
||||
{B_F3_KEY, 0x3d},
|
||||
{B_F4_KEY, 0x3e},
|
||||
{B_F5_KEY, 0x3f},
|
||||
{B_F6_KEY, 0x40},
|
||||
{B_F7_KEY, 0x41},
|
||||
{B_F8_KEY, 0x42},
|
||||
{B_F9_KEY, 0x43},
|
||||
{B_F10_KEY, 0x44},
|
||||
{B_F11_KEY, 0x57},
|
||||
{B_F12_KEY, 0x58},
|
||||
{B_PRINT_KEY, 0x137},
|
||||
{B_SCROLL_KEY, 0x46},
|
||||
{B_PAUSE_KEY, 0x145},
|
||||
{B_KATAKANA_HIRAGANA, 0x70},
|
||||
{B_HANKAKU_ZENKAKU, 0x76},
|
||||
|
||||
{0x01, 0x01}, /* Escape */
|
||||
{0x11, 0x29},
|
||||
{0x12, 0x02},
|
||||
{0x13, 0x03},
|
||||
{0x14, 0x04},
|
||||
{0x15, 0x05},
|
||||
{0x16, 0x06},
|
||||
{0x17, 0x07},
|
||||
{0x18, 0x08},
|
||||
{0x19, 0x09},
|
||||
{0x1a, 0x0a},
|
||||
{0x1b, 0x0b},
|
||||
{0x1c, 0x0c},
|
||||
{0x1d, 0x0d},
|
||||
{0x1e, 0x0e}, /* Backspace */
|
||||
{0x1f, 0x152}, /* Insert */
|
||||
{0x20, 0x147}, /* Home */
|
||||
{0x21, 0x149}, /* Page Up */
|
||||
{0x22, 0x45},
|
||||
{0x23, 0x135},
|
||||
{0x24, 0x37},
|
||||
{0x25, 0x4a},
|
||||
{0x26, 0x0f}, /* Tab */
|
||||
{0x27, 0x10},
|
||||
{0x28, 0x11},
|
||||
{0x29, 0x12},
|
||||
{0x2a, 0x13},
|
||||
{0x2b, 0x14},
|
||||
{0x2c, 0x15},
|
||||
{0x2d, 0x16},
|
||||
{0x2e, 0x17},
|
||||
{0x2f, 0x18},
|
||||
{0x30, 0x19},
|
||||
{0x31, 0x1a},
|
||||
{0x32, 0x1b},
|
||||
{0x33, 0x2b},
|
||||
{0x34, 0x153}, /* Delete */
|
||||
{0x35, 0x14f}, /* End */
|
||||
{0x36, 0x151}, /* Page Down */
|
||||
{0x37, 0x47},
|
||||
{0x38, 0x48},
|
||||
{0x39, 0x49},
|
||||
{0x3a, 0x4e},
|
||||
{0x3b, 0x3a},
|
||||
{0x3c, 0x1e},
|
||||
{0x3d, 0x1f},
|
||||
{0x3e, 0x20},
|
||||
{0x3f, 0x21},
|
||||
{0x40, 0x22},
|
||||
{0x41, 0x23},
|
||||
{0x42, 0x24},
|
||||
{0x43, 0x25},
|
||||
{0x44, 0x26},
|
||||
{0x45, 0x27},
|
||||
{0x46, 0x28},
|
||||
{0x47, 0x1c}, /* Enter */
|
||||
{0x48, 0x4b},
|
||||
{0x49, 0x4c},
|
||||
{0x4a, 0x4d},
|
||||
{0x4b, 0x2a},
|
||||
{0x4c, 0x2c},
|
||||
{0x4d, 0x2d},
|
||||
{0x4e, 0x2e},
|
||||
{0x4f, 0x2f},
|
||||
{0x50, 0x30},
|
||||
{0x51, 0x31},
|
||||
{0x52, 0x32},
|
||||
{0x53, 0x33},
|
||||
{0x54, 0x34},
|
||||
{0x55, 0x35},
|
||||
{0x56, 0x36},
|
||||
{0x57, 0x148}, /* up arrow */
|
||||
{0x58, 0x51},
|
||||
{0x59, 0x50},
|
||||
{0x5a, 0x4f},
|
||||
{0x5b, 0x11c},
|
||||
{0x5c, 0x1d},
|
||||
{0x5d, 0x38},
|
||||
{0x5e, 0x39}, /* space bar */
|
||||
{0x5f, 0x138},
|
||||
{0x60, 0x11d},
|
||||
{0x61, 0x14b}, /* left arrow */
|
||||
{0x62, 0x150}, /* down arrow */
|
||||
{0x63, 0x14d}, /* right arrow */
|
||||
{0x64, 0x52},
|
||||
{0x65, 0x53},
|
||||
{0x66, 0x15b},
|
||||
{0x67, 0x15c},
|
||||
{0x68, 0x15d},
|
||||
{0x69, 0x56},
|
||||
{0x7e, 0x137}, /* System Request */
|
||||
{0x7f, 0x145}, /* Break */
|
||||
};
|
||||
129
src/qt/cocoa_keyboard.hpp
Normal file
129
src/qt/cocoa_keyboard.hpp
Normal file
@@ -0,0 +1,129 @@
|
||||
static std::array<uint32_t, 127> cocoa_keycodes = { /* key names in parentheses are not declared by Apple headers */
|
||||
0x1e, /* ANSI_A */
|
||||
0x1f, /* ANSI_S */
|
||||
0x20, /* ANSI_D */
|
||||
0x21, /* ANSI_F */
|
||||
0x23, /* ANSI_H */
|
||||
0x22, /* ANSI_G */
|
||||
0x2c, /* ANSI_Z */
|
||||
0x2d, /* ANSI_X */
|
||||
0x2e, /* ANSI_C */
|
||||
0x2f, /* ANSI_V */
|
||||
0x56, /* ISO_Section */
|
||||
0x30, /* ANSI_B */
|
||||
0x10, /* ANSI_Q */
|
||||
0x11, /* ANSI_W */
|
||||
0x12, /* ANSI_E */
|
||||
0x13, /* ANSI_R */
|
||||
0x15, /* ANSI_Y */
|
||||
0x14, /* ANSI_T */
|
||||
0x02, /* ANSI_1 */
|
||||
0x03, /* ANSI_2 */
|
||||
0x04, /* ANSI_3 */
|
||||
0x05, /* ANSI_4 */
|
||||
0x07, /* ANSI_6 */
|
||||
0x06, /* ANSI_5 */
|
||||
0x0d, /* ANSI_Equal */
|
||||
0x0a, /* ANSI_9 */
|
||||
0x08, /* ANSI_7 */
|
||||
0x0c, /* ANSI_Minus */
|
||||
0x09, /* ANSI_8 */
|
||||
0x0b, /* ANSI_0 */
|
||||
0x1b, /* ANSI_RightBracket */
|
||||
0x18, /* ANSI_O */
|
||||
0x16, /* ANSI_U */
|
||||
0x1a, /* ANSI_LeftBracket */
|
||||
0x17, /* ANSI_I */
|
||||
0x19, /* ANSI_P */
|
||||
0x1c, /* Return */
|
||||
0x26, /* ANSI_L */
|
||||
0x24, /* ANSI_J */
|
||||
0x28, /* ANSI_Quote */
|
||||
0x25, /* ANSI_K */
|
||||
0x27, /* ANSI_Semicolon */
|
||||
0x2b, /* ANSI_Backslash */
|
||||
0x33, /* ANSI_Comma */
|
||||
0x35, /* ANSI_Slash */
|
||||
0x31, /* ANSI_N */
|
||||
0x32, /* ANSI_M */
|
||||
0x34, /* ANSI_Period */
|
||||
0x0f, /* Tab */
|
||||
0x39, /* Space */
|
||||
0x29, /* ANSI_Grave */
|
||||
0x0e, /* Delete => Backspace */
|
||||
0x11c, /* (ANSI_KeypadEnter) */
|
||||
0x01, /* Escape */
|
||||
0x15c, /* (RightCommand) => Right Windows */
|
||||
0x15b, /* (Left)Command => Left Windows */
|
||||
0x2a, /* Shift */
|
||||
0x3a, /* CapsLock */
|
||||
0x38, /* Option */
|
||||
0x1d, /* Control */
|
||||
0x36, /* RightShift */
|
||||
0x138, /* RightOption */
|
||||
0x11d, /* RightControl */
|
||||
0x15c, /* Function */
|
||||
0x5e, /* F17 => F14 */
|
||||
0x53, /* ANSI_KeypadDecimal */
|
||||
0,
|
||||
0x37, /* ANSI_KeypadMultiply */
|
||||
0,
|
||||
0x4e, /* ANSI_KeypadPlus */
|
||||
0,
|
||||
0x45, /* ANSI_KeypadClear => Num Lock (location equivalent) */
|
||||
0x130, /* VolumeUp */
|
||||
0x12e, /* VolumeDown */
|
||||
0x120, /* Mute */
|
||||
0x135, /* ANSI_KeypadDivide */
|
||||
0x11c, /* ANSI_KeypadEnter */
|
||||
0,
|
||||
0x4a, /* ANSI_KeypadMinus */
|
||||
0x5f, /* F18 => F15 */
|
||||
0, /* F19 */
|
||||
0x59, /* ANSI_KeypadEquals */
|
||||
0x52, /* ANSI_Keypad0 */
|
||||
0x4f, /* ANSI_Keypad1 */
|
||||
0x50, /* ANSI_Keypad2 */
|
||||
0x51, /* ANSI_Keypad3 */
|
||||
0x4b, /* ANSI_Keypad4 */
|
||||
0x4c, /* ANSI_Keypad5 */
|
||||
0x4d, /* ANSI_Keypad6 */
|
||||
0x47, /* ANSI_Keypad7 */
|
||||
0, /* F20 */
|
||||
0x48, /* ANSI_Keypad8 */
|
||||
0x49, /* ANSI_Keypad9 */
|
||||
0x7d, /* JIS_Yen */
|
||||
0x73, /* JIS_Underscore */
|
||||
0x5c, /* JIS_KeypadComma */
|
||||
0x3f, /* F5 */
|
||||
0x40, /* F6 */
|
||||
0x41, /* F7 */
|
||||
0x3d, /* F3 */
|
||||
0x42, /* F8 */
|
||||
0x43, /* F9 */
|
||||
0x7b, /* JIS_Eisu => muhenkan (location equivalent) */
|
||||
0x57, /* F11 */
|
||||
0x79, /* JIS_Kana => henkan (location equivalent) */
|
||||
0x137, /* F13 => SysRq (location equivalent) */
|
||||
0x5d, /* F16 => F13 */
|
||||
0x46, /* F14 => Scroll Lock (location equivalent) */
|
||||
0,
|
||||
0x44, /* F10 */
|
||||
0x15d, /* (Menu) */
|
||||
0x58, /* F12 */
|
||||
0,
|
||||
0x145, /* F15 => Pause (location equivalent) */
|
||||
0x152, /* Help => Insert (location equivalent) */
|
||||
0x147, /* Home */
|
||||
0x149, /* PageUp */
|
||||
0x153, /* ForwardDelete */
|
||||
0x3e, /* F4 */
|
||||
0x14f, /* End */
|
||||
0x3c, /* F2 */
|
||||
0x151, /* PageDown */
|
||||
0x3b, /* F1 */
|
||||
0x14b, /* LeftArrow */
|
||||
0x14d, /* RightArrow */
|
||||
0x150, /* DownArrow */
|
||||
0x148, /* UpArrow */
|
||||
};
|
||||
163
src/qt/evdev_keyboard.cpp
Normal file
163
src/qt/evdev_keyboard.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* evdev keyboard input module.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: RichardG, <richardg867@gmail.com>
|
||||
*
|
||||
* Copyright 2023 RichardG.
|
||||
*/
|
||||
#include <unordered_map>
|
||||
#include <QtDebug>
|
||||
|
||||
static std::unordered_map<uint32_t, uint16_t> evdev_keycodes = {
|
||||
{184, 0x46}, /* F14 => Scroll Lock (for Apple keyboards) */
|
||||
{86, 0x56}, /* 102ND */
|
||||
{87, 0x57}, /* F11 */
|
||||
{88, 0x58}, /* F12 */
|
||||
{186, 0x5d}, /* F16 => F13 */
|
||||
{187, 0x5e}, /* F17 => F14 */
|
||||
{188, 0x5f}, /* F18 => F15 */
|
||||
|
||||
/* Japanese keys. */
|
||||
{95, 0x5c}, /* KPJPCOMMA */
|
||||
{93, 0x70}, /* KATAKANAHIRAGANA */
|
||||
{89, 0x73}, /* RO */
|
||||
{85, 0x76}, /* ZENKAKUHANKAKU */
|
||||
{91, 0x77}, /* HIRAGANA */
|
||||
{90, 0x78}, /* KATAKANA */
|
||||
{92, 0x79}, /* HENKAN */
|
||||
{94, 0x7b}, /* MUHENKAN */
|
||||
{124, 0x7d}, /* YEN */
|
||||
{121, 0x7e}, /* KPCOMMA */
|
||||
|
||||
/* Korean keys. */
|
||||
{123, 0xf1}, /* HANJA */
|
||||
{122, 0xf2}, /* HANGUL */
|
||||
|
||||
{96, 0x11c}, /* KPENTER */
|
||||
{97, 0x11d}, /* RIGHTCTRL */
|
||||
{98, 0x135}, /* KPSLASH */
|
||||
{99, 0x137}, /* SYSRQ */
|
||||
{183, 0x137}, /* F13 => SysRq (for Apple keyboards) */
|
||||
{100, 0x138}, /* RIGHTALT */
|
||||
{119, 0x145}, /* PAUSE */
|
||||
{411, 0x145}, /* BREAK */
|
||||
{185, 0x145}, /* F15 => Pause (for Apple keyboards) */
|
||||
{102, 0x147}, /* HOME */
|
||||
{103, 0x148}, /* UP */
|
||||
{104, 0x149}, /* PAGEUP */
|
||||
{105, 0x14b}, /* LEFT */
|
||||
{106, 0x14d}, /* RIGHT */
|
||||
{107, 0x14f}, /* END */
|
||||
{108, 0x150}, /* DOWN */
|
||||
{109, 0x151}, /* PAGEDOWN */
|
||||
{110, 0x152}, /* INSERT */
|
||||
{111, 0x153}, /* DELETE */
|
||||
|
||||
{125, 0x15b}, /* LEFTMETA */
|
||||
{126, 0x15c}, /* RIGHTMETA */
|
||||
{127, 0x15d}, /* COMPOSE => Menu */
|
||||
|
||||
/* Multimedia keys. Guideline is to try and follow the Microsoft standard, then
|
||||
fill in remaining scancodes with OEM-specific keys for redundancy sake. Keys
|
||||
marked with # are not translated into evdev codes by the standard atkbd driver. */
|
||||
{634, 0x54}, /* SELECTIVE_SCREENSHOT# => Alt+SysRq */
|
||||
{117, 0x59}, /* KPEQUAL */
|
||||
{418, 0x6a}, /* ZOOMIN# => Logitech */
|
||||
{420, 0x6b}, /* ZOOMRESET# => Logitech */
|
||||
{223, 0x6d}, /* CANCEL# => Logitech */
|
||||
{132, 0x101}, /* # Logitech Task Select */
|
||||
{148, 0x102}, /* PROG1# => Samsung */
|
||||
{149, 0x103}, /* PROG2# => Samsung */
|
||||
{419, 0x104}, /* ZOOMOUT# => Logitech */
|
||||
{144, 0x105}, /* FILE# => Messenger/Files */
|
||||
{216, 0x105}, /* CHAT# => Messenger/Files */
|
||||
{430, 0x105}, /* MESSENGER# */
|
||||
{182, 0x107}, /* REDO# */
|
||||
{131, 0x108}, /* UNDO# */
|
||||
{135, 0x10a}, /* PASTE# */
|
||||
{177, 0x10b}, /* SCROLLUP# => normal speed */
|
||||
{165, 0x110}, /* PREVIOUSSONG */
|
||||
{136, 0x112}, /* FIND# => Logitech */
|
||||
{421, 0x113}, /* WORDPROCESSOR# => Word */
|
||||
{423, 0x114}, /* SPREADSHEET# => Excel */
|
||||
{397, 0x115}, /* CALENDAR# */
|
||||
{433, 0x116}, /* LOGOFF# */
|
||||
{137, 0x117}, /* CUT# */
|
||||
{133, 0x118}, /* COPY# */
|
||||
{163, 0x119}, /* NEXTSONG */
|
||||
{154, 0x11e}, /* CYCLEWINDOWS => Application Right (no left counterpart) */
|
||||
{113, 0x120}, /* MUTE */
|
||||
{140, 0x121}, /* CALC */
|
||||
{164, 0x122}, /* PLAYPAUSE */
|
||||
{432, 0x123}, /* SPELLCHECK# */
|
||||
{166, 0x124}, /* STOPCD */
|
||||
{139, 0x126}, /* MENU# => Shortcut/Menu/Help for a few OEMs */
|
||||
{114, 0x12e}, /* VOL- */
|
||||
{160, 0x12f}, /* CLOSECD# => Logitech Eject */
|
||||
{161, 0x12f}, /* EJECTCD# => Logitech */
|
||||
{162, 0x12f}, /* EJECTCLOSECD# => Logitech */
|
||||
{115, 0x130}, /* VOL+ */
|
||||
{150, 0x132}, /* WWW# */
|
||||
{172, 0x132}, /* HOMEPAGE */
|
||||
{138, 0x13b}, /* HELP# */
|
||||
{213, 0x13c}, /* SOUND# => My Music/Office Home */
|
||||
{360, 0x13c}, /* VENDOR# => My Music/Office Home */
|
||||
{204, 0x13d}, /* DASHBOARD# => Task Pane */
|
||||
{181, 0x13e}, /* NEW# */
|
||||
{134, 0x13f}, /* OPEN# */
|
||||
{206, 0x140}, /* CLOSE# */
|
||||
{232, 0x141}, /* REPLY# */
|
||||
{233, 0x142}, /* FORWARDMAIL# */
|
||||
{231, 0x143}, /* SEND# */
|
||||
{151, 0x144}, /* MSDOS# */
|
||||
{112, 0x14c}, /* MACRO */
|
||||
{179, 0x14c}, /* KPLEFTPAREN# */
|
||||
{118, 0x14e}, /* KPPLUSMINUS */
|
||||
{235, 0x155}, /* DOCUMENTS# => Logitech */
|
||||
{234, 0x157}, /* SAVE# */
|
||||
{210, 0x158}, /* PRINT# */
|
||||
{116, 0x15e}, /* POWER */
|
||||
{142, 0x15f}, /* SLEEP */
|
||||
{143, 0x163}, /* WAKEUP */
|
||||
{180, 0x164}, /* KPRIGHTPAREN# */
|
||||
{212, 0x164}, /* CAMERA# => My Pictures */
|
||||
{217, 0x165}, /* SEARCH */
|
||||
{156, 0x166}, /* BOOKMARKS => Favorites */
|
||||
{364, 0x166}, /* FAVORITES# */
|
||||
{173, 0x167}, /* REFRESH */
|
||||
{128, 0x168}, /* STOP */
|
||||
{159, 0x169}, /* FORWARD */
|
||||
{158, 0x16a}, /* BACK */
|
||||
{157, 0x16b}, /* COMPUTER */
|
||||
{155, 0x16c}, /* MAIL */
|
||||
{215, 0x16c}, /* EMAIL# */
|
||||
{226, 0x16d}, /* MEDIA */
|
||||
{167, 0x178}, /* RECORD# => Logitech */
|
||||
{152, 0x17a}, /* COFFEE/SCREENLOCK# */
|
||||
{178, 0x18b}, /* SCROLLDOWN# => normal speed */
|
||||
};
|
||||
|
||||
uint16_t
|
||||
evdev_translate(uint32_t keycode)
|
||||
{
|
||||
/* "for 1-83 (0x01-0x53) scancode equals keycode" */
|
||||
auto ret = (keycode <= 0x53) ? keycode : evdev_keycodes[keycode];
|
||||
|
||||
if (!ret)
|
||||
qWarning() << "Evdev Keyboard: Unknown key" << keycode;
|
||||
#if 0
|
||||
else
|
||||
qInfo() << "Evdev Keyboard: Key" << keycode << "scancode" << QString::number(ret, 16);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
20
src/qt/evdev_keyboard.hpp
Normal file
20
src/qt/evdev_keyboard.hpp
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Definitions for evdev keyboard input module.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: RichardG, <richardg867@gmail.com>
|
||||
*
|
||||
* Copyright 2023 RichardG.
|
||||
*/
|
||||
#ifndef EVDEV_KEYBOARD_HPP
|
||||
#define EVDEV_KEYBOARD_HPP
|
||||
uint16_t evdev_translate(uint32_t keycode);
|
||||
#endif
|
||||
@@ -206,13 +206,13 @@ msgid "&About 86Box..."
|
||||
msgstr "關於 86Box(&A)..."
|
||||
|
||||
msgid "&New image..."
|
||||
msgstr "新增鏡像(&N)..."
|
||||
msgstr "新增映像(&N)..."
|
||||
|
||||
msgid "&Existing image..."
|
||||
msgstr "開啟已存在的鏡像(&E)..."
|
||||
msgstr "開啟已存在的映像(&E)..."
|
||||
|
||||
msgid "Existing image (&Write-protected)..."
|
||||
msgstr "開啟已存在的鏡像並寫保護(&W)..."
|
||||
msgstr "開啟已存在的映像並寫保護(&W)..."
|
||||
|
||||
msgid "&Record"
|
||||
msgstr "錄製(&R)"
|
||||
@@ -227,10 +227,10 @@ msgid "&Fast forward to the end"
|
||||
msgstr "快進至終點(&F)"
|
||||
|
||||
msgid "E&ject"
|
||||
msgstr "彈出(&J)"
|
||||
msgstr "退出(&J)"
|
||||
|
||||
msgid "&Image..."
|
||||
msgstr "鏡像(&I)..."
|
||||
msgstr "映像(&I)..."
|
||||
|
||||
msgid "E&xport to 86F..."
|
||||
msgstr "匯出為 86F 格式(&x)..."
|
||||
@@ -242,7 +242,7 @@ msgid "E&mpty"
|
||||
msgstr "空置光碟機(&M)"
|
||||
|
||||
msgid "&Reload previous image"
|
||||
msgstr "載入上一個鏡像(&R)"
|
||||
msgstr "載入上一個映像(&R)"
|
||||
|
||||
msgid "&Folder..."
|
||||
msgstr "資料夾(&F)..."
|
||||
@@ -272,7 +272,7 @@ msgid "&VSync"
|
||||
msgstr "垂直同步(&V)"
|
||||
|
||||
msgid "&Select shader..."
|
||||
msgstr "選擇著色器(&S)..."
|
||||
msgstr "選取著色器(&S)..."
|
||||
|
||||
msgid "&Remove shader"
|
||||
msgstr "移除著色器(&R)"
|
||||
@@ -284,7 +284,7 @@ msgid "Sound Gain"
|
||||
msgstr "音量增益"
|
||||
|
||||
msgid "New Image"
|
||||
msgstr "新增鏡像"
|
||||
msgstr "新增映像"
|
||||
|
||||
msgid "Settings"
|
||||
msgstr "設定"
|
||||
@@ -533,7 +533,7 @@ msgid "&New..."
|
||||
msgstr "新增(&N)..."
|
||||
|
||||
msgid "&Existing..."
|
||||
msgstr "已有鏡像(&E)..."
|
||||
msgstr "已有映像(&E)..."
|
||||
|
||||
msgid "&Remove"
|
||||
msgstr "移除(&R)"
|
||||
@@ -566,10 +566,10 @@ msgid "Type:"
|
||||
msgstr "類型:"
|
||||
|
||||
msgid "Image Format:"
|
||||
msgstr "鏡像格式:"
|
||||
msgstr "映像格式:"
|
||||
|
||||
msgid "Block Size:"
|
||||
msgstr "塊大小:"
|
||||
msgstr "區塊大小:"
|
||||
|
||||
msgid "Floppy drives:"
|
||||
msgstr "軟碟機:"
|
||||
@@ -647,10 +647,10 @@ msgid "ZIP %03i %i (%s): %ls"
|
||||
msgstr "ZIP %03i %i (%s): %ls"
|
||||
|
||||
msgid "ZIP images"
|
||||
msgstr "ZIP 鏡像"
|
||||
msgstr "ZIP 映像"
|
||||
|
||||
msgid "86Box could not find any usable ROM images.\n\nPlease <a href=\"https://github.com/86Box/roms/releases/latest\">download</a> a ROM set and extract it into the \"roms\" directory."
|
||||
msgstr "86Box 找不到任何可用的 ROM 鏡像。\n\n請<a href=\"https://github.com/86Box/roms/releases/latest\">下載</a>ROM 包並將其解壓到 \"roms\" 資料夾。"
|
||||
msgstr "86Box 找不到任何可用的 ROM 映像。\n\n請<a href=\"https://github.com/86Box/roms/releases/latest\">下載</a>ROM 包並將其解壓到 \"roms\" 資料夾。"
|
||||
|
||||
msgid "(empty)"
|
||||
msgstr "(空)"
|
||||
@@ -668,13 +668,13 @@ msgid "Off"
|
||||
msgstr "關"
|
||||
|
||||
msgid "All images"
|
||||
msgstr "所有鏡像"
|
||||
msgstr "所有映像"
|
||||
|
||||
msgid "Basic sector images"
|
||||
msgstr "基本磁區鏡像"
|
||||
msgstr "基本磁區映像"
|
||||
|
||||
msgid "Surface images"
|
||||
msgstr "表面鏡像"
|
||||
msgstr "表面映像"
|
||||
|
||||
msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine."
|
||||
msgstr "由於 roms/machines 資料夾中缺少合適的 ROM,機型 \"%hs\" 不可用。將切換到其他可用機型。"
|
||||
@@ -710,7 +710,7 @@ msgid "Floppy & CD-ROM drives"
|
||||
msgstr "軟碟/光碟機"
|
||||
|
||||
msgid "Other removable devices"
|
||||
msgstr "其他可移除裝置"
|
||||
msgstr "其他卸除式裝置"
|
||||
|
||||
msgid "Other peripherals"
|
||||
msgstr "其他周邊裝置"
|
||||
@@ -806,10 +806,10 @@ msgid "Floppy %i (%s): %ls"
|
||||
msgstr "軟碟 %i (%s): %ls"
|
||||
|
||||
msgid "Advanced sector images"
|
||||
msgstr "進階磁區鏡像"
|
||||
msgstr "進階磁區映像"
|
||||
|
||||
msgid "Flux images"
|
||||
msgstr "Flux 鏡像"
|
||||
msgstr "Flux 映像"
|
||||
|
||||
msgid "Unable to initialize FreeType"
|
||||
msgstr "無法初始化 FreeType"
|
||||
@@ -830,7 +830,7 @@ msgid "MO %i (%ls): %ls"
|
||||
msgstr "磁光碟 %i (%ls): %ls"
|
||||
|
||||
msgid "MO images"
|
||||
msgstr "磁光碟鏡像"
|
||||
msgstr "磁光碟映像"
|
||||
|
||||
msgid "Welcome to 86Box!"
|
||||
msgstr "歡迎使用 86Box!"
|
||||
@@ -845,13 +845,13 @@ msgid "No ROMs found"
|
||||
msgstr "找不到 ROM"
|
||||
|
||||
msgid "Do you want to save the settings?"
|
||||
msgstr "要保存設定嗎?"
|
||||
msgstr "要儲存設定嗎?"
|
||||
|
||||
msgid "This will hard reset the emulated machine."
|
||||
msgstr "此操作將硬重設模擬器。"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "保存"
|
||||
msgstr "儲存"
|
||||
|
||||
msgid "About 86Box"
|
||||
msgstr "關於 86Box"
|
||||
@@ -893,7 +893,7 @@ msgid "libgs"
|
||||
msgstr "libgs"
|
||||
|
||||
msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files."
|
||||
msgstr " 是將 PostScript 檔案轉換為 PDF 所需要的庫。\n\n使用通用 PostScript 印表機列印的文件將被保存為 PostScript (.ps) 檔案。"
|
||||
msgstr " 是將 PostScript 檔案轉換為 PDF 所需要的庫。\n\n使用通用 PostScript 印表機列印的文件將被儲存為 PostScript (.ps) 檔案。"
|
||||
|
||||
msgid "libfluidsynth.dll"
|
||||
msgstr "libfluidsynth.dll"
|
||||
@@ -920,7 +920,7 @@ msgid "Don't reset"
|
||||
msgstr "不重設"
|
||||
|
||||
msgid "CD-ROM images"
|
||||
msgstr "光碟鏡像"
|
||||
msgstr "光碟映像"
|
||||
|
||||
msgid "%hs Device Configuration"
|
||||
msgstr "%hs 裝置配置"
|
||||
@@ -947,13 +947,13 @@ msgid "Cassette: %s"
|
||||
msgstr "磁帶: %s"
|
||||
|
||||
msgid "Cassette images"
|
||||
msgstr "磁帶鏡像"
|
||||
msgstr "磁帶映像"
|
||||
|
||||
msgid "Cartridge %i: %ls"
|
||||
msgstr "卡帶 %i: %ls"
|
||||
|
||||
msgid "Cartridge images"
|
||||
msgstr "卡帶鏡像"
|
||||
msgstr "卡帶映像"
|
||||
|
||||
msgid "Error initializing renderer"
|
||||
msgstr "初始化渲染器時出錯"
|
||||
@@ -1004,13 +1004,13 @@ msgid "Add Existing Hard Disk"
|
||||
msgstr "添加已存在的硬碟"
|
||||
|
||||
msgid "HDI disk images cannot be larger than 4 GB."
|
||||
msgstr "HDI 磁碟鏡像不能超過 4 GB。"
|
||||
msgstr "HDI 磁碟映像不能超過 4 GB。"
|
||||
|
||||
msgid "Disk images cannot be larger than 127 GB."
|
||||
msgstr "磁碟鏡像不能超過 127 GB。"
|
||||
msgstr "磁碟映像不能超過 127 GB。"
|
||||
|
||||
msgid "Hard disk images"
|
||||
msgstr "硬碟鏡像"
|
||||
msgstr "硬碟映像"
|
||||
|
||||
msgid "Unable to read file"
|
||||
msgstr "無法讀取檔案"
|
||||
@@ -1019,37 +1019,37 @@ msgid "Unable to write file"
|
||||
msgstr "無法寫入檔案"
|
||||
|
||||
msgid "HDI or HDX images with a sector size other than 512 are not supported."
|
||||
msgstr "不支援非 512 位元組磁區大小的 HDI 或 HDX 鏡像。"
|
||||
msgstr "不支援非 512 位元組磁區大小的 HDI 或 HDX 映像。"
|
||||
|
||||
msgid "USB is not yet supported"
|
||||
msgstr "尚未支援 USB"
|
||||
|
||||
msgid "Disk image file already exists"
|
||||
msgstr "磁碟鏡像檔案已存在"
|
||||
msgstr "磁碟映像檔案已存在"
|
||||
|
||||
msgid "Please specify a valid file name."
|
||||
msgstr "請指定有效的檔案名。"
|
||||
|
||||
msgid "Disk image created"
|
||||
msgstr "已創建磁碟鏡像"
|
||||
msgstr "已創建磁碟映像"
|
||||
|
||||
msgid "Make sure the file exists and is readable."
|
||||
msgstr "請確定此檔案已存在並可讀取。"
|
||||
|
||||
msgid "Make sure the file is being saved to a writable directory."
|
||||
msgstr "請確定此檔案保存在可寫目錄中。"
|
||||
msgstr "請確定此檔案儲存在可寫目錄中。"
|
||||
|
||||
msgid "Disk image too large"
|
||||
msgstr "磁碟鏡像太大"
|
||||
msgstr "磁碟映像太大"
|
||||
|
||||
msgid "Remember to partition and format the newly-created drive."
|
||||
msgstr "請記得為新創建的鏡像分區並格式化。"
|
||||
msgstr "請記得為新創建的映像分區並格式化。"
|
||||
|
||||
msgid "The selected file will be overwritten. Are you sure you want to use it?"
|
||||
msgstr "選定的檔案將被覆蓋。確定繼續使用此檔案嗎?"
|
||||
|
||||
msgid "Unsupported disk image"
|
||||
msgstr "不支援的磁碟鏡像"
|
||||
msgstr "不支援的磁碟映像"
|
||||
|
||||
msgid "Overwrite"
|
||||
msgstr "覆蓋"
|
||||
@@ -1058,13 +1058,13 @@ msgid "Don't overwrite"
|
||||
msgstr "不覆蓋"
|
||||
|
||||
msgid "Raw image (.img)"
|
||||
msgstr "原始鏡像 (.img)"
|
||||
msgstr "原始映像 (.img)"
|
||||
|
||||
msgid "HDI image (.hdi)"
|
||||
msgstr "HDI 鏡像 (.hdi)"
|
||||
msgstr "HDI 映像 (.hdi)"
|
||||
|
||||
msgid "HDX image (.hdx)"
|
||||
msgstr "HDX 鏡像 (.hdx)"
|
||||
msgstr "HDX 映像 (.hdx)"
|
||||
|
||||
msgid "Fixed-size VHD (.vhd)"
|
||||
msgstr "固定大小 VHD (.vhd)"
|
||||
@@ -1076,19 +1076,19 @@ msgid "Differencing VHD (.vhd)"
|
||||
msgstr "差分 VHD (.vhd)"
|
||||
|
||||
msgid "Large blocks (2 MB)"
|
||||
msgstr "大塊 (2 MB)"
|
||||
msgstr "大區塊 (2 MB)"
|
||||
|
||||
msgid "Small blocks (512 KB)"
|
||||
msgstr "小塊 (512 KB)"
|
||||
msgstr "小區塊 (512 KB)"
|
||||
|
||||
msgid "VHD files"
|
||||
msgstr "VHD 檔案"
|
||||
|
||||
msgid "Select the parent VHD"
|
||||
msgstr "選擇父 VHD 檔案"
|
||||
msgstr "選取父 VHD 檔案"
|
||||
|
||||
msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?"
|
||||
msgstr "父映像可能在創建差異鏡像後被修改。\n\n如果鏡像檔案被移動或複製,或創建此磁碟的程式中存在錯誤,也可能發生這種情況。\n\n是否需要修復時間戳?"
|
||||
msgstr "父映像可能在創建差異映像後被修改。\n\n如果映像檔案被移動或複製,或創建此磁碟的程式中存在錯誤,也可能發生這種情況。\n\n是否需要修復時間戳?"
|
||||
|
||||
msgid "Parent and child disk timestamps do not match"
|
||||
msgstr "父碟與子碟的時間戳不匹配"
|
||||
@@ -1175,34 +1175,34 @@ msgid "ZIP 100"
|
||||
msgstr "ZIP 100"
|
||||
|
||||
msgid "3.5\" 128 MB (ISO 10090)"
|
||||
msgstr "3.5 英寸 128 MB (ISO 10090)"
|
||||
msgstr "3.5 英吋 128 MB (ISO 10090)"
|
||||
|
||||
msgid "3.5\" 230 MB (ISO 13963)"
|
||||
msgstr "3.5 英寸 230 MB (ISO 13963)"
|
||||
msgstr "3.5 英吋 230 MB (ISO 13963)"
|
||||
|
||||
msgid "3.5\" 540 MB (ISO 15498)"
|
||||
msgstr "3.5 英寸 540 MB (ISO 15498)"
|
||||
msgstr "3.5 英吋 540 MB (ISO 15498)"
|
||||
|
||||
msgid "3.5\" 640 MB (ISO 15498)"
|
||||
msgstr "3.5 英寸 640 MB (ISO 15498)"
|
||||
msgstr "3.5 英吋 640 MB (ISO 15498)"
|
||||
|
||||
msgid "3.5\" 1.3 GB (GigaMO)"
|
||||
msgstr "3.5 英寸 1.3 GB (GigaMO)"
|
||||
msgstr "3.5 英吋 1.3 GB (GigaMO)"
|
||||
|
||||
msgid "3.5\" 2.3 GB (GigaMO 2)"
|
||||
msgstr "3.5 英寸 2.3 GB (GigaMO 2)"
|
||||
msgstr "3.5 英吋 2.3 GB (GigaMO 2)"
|
||||
|
||||
msgid "5.25\" 600 MB"
|
||||
msgstr "5.25 英寸 600 MB"
|
||||
msgstr "5.25 英吋 600 MB"
|
||||
|
||||
msgid "5.25\" 650 MB"
|
||||
msgstr "5.25 英寸 650 MB"
|
||||
msgstr "5.25 英吋 650 MB"
|
||||
|
||||
msgid "5.25\" 1 GB"
|
||||
msgstr "5.25 英寸 1 GB"
|
||||
msgstr "5.25 英吋 1 GB"
|
||||
|
||||
msgid "5.25\" 1.3 GB"
|
||||
msgstr "5.25 英寸 1.3 GB"
|
||||
msgstr "5.25 英吋 1.3 GB"
|
||||
|
||||
msgid "Perfect RPM"
|
||||
msgstr "標準轉速 (RPM)"
|
||||
@@ -1218,4 +1218,3 @@ msgstr "低於標準轉速的 2%"
|
||||
|
||||
msgid "(System Default)"
|
||||
msgstr "(系統預設)"
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ extern "C" {
|
||||
#include <86box/86box.h>
|
||||
#include <86box/hdd.h>
|
||||
#include "../disk/minivhd/minivhd.h"
|
||||
#include "../disk/minivhd/minivhd_util.h"
|
||||
}
|
||||
|
||||
#include <thread>
|
||||
|
||||
@@ -138,7 +138,11 @@ main_thread_fn()
|
||||
}
|
||||
|
||||
is_quit = 1;
|
||||
QTimer::singleShot(0, QApplication::instance(), []() { QApplication::instance()->quit(); });
|
||||
if (gfxcard[1]) {
|
||||
ui_deinit_monitor(1);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
}
|
||||
QTimer::singleShot(0, QApplication::instance(), []() { QApplication::processEvents(); QApplication::instance()->quit(); });
|
||||
}
|
||||
|
||||
static std::thread *main_thread;
|
||||
|
||||
@@ -96,8 +96,17 @@ extern int qt_nvr_save(void);
|
||||
#include "qt_util.hpp"
|
||||
|
||||
#if defined __unix__ && !defined __HAIKU__
|
||||
# ifdef WAYLAND
|
||||
# include "wl_mouse.hpp"
|
||||
# ifndef Q_OS_MACOS
|
||||
# include "evdev_keyboard.hpp"
|
||||
# endif
|
||||
# ifdef XKBCOMMON
|
||||
# include "xkbcommon_keyboard.hpp"
|
||||
# ifdef XKBCOMMON_X11
|
||||
# include "xkbcommon_x11_keyboard.hpp"
|
||||
# endif
|
||||
# ifdef WAYLAND
|
||||
# include "xkbcommon_wl_keyboard.hpp"
|
||||
# endif
|
||||
# endif
|
||||
# include <X11/Xlib.h>
|
||||
# include <X11/keysym.h>
|
||||
@@ -106,6 +115,7 @@ extern int qt_nvr_save(void);
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
# include "cocoa_keyboard.hpp"
|
||||
// The namespace is required to avoid clashing typedefs; we only use this
|
||||
// header for its #defines anyway.
|
||||
namespace IOKit {
|
||||
@@ -116,6 +126,7 @@ namespace IOKit {
|
||||
#ifdef __HAIKU__
|
||||
# include <os/AppKit.h>
|
||||
# include <os/InterfaceKit.h>
|
||||
# include "be_keyboard.hpp"
|
||||
|
||||
extern MainWindow *main_window;
|
||||
|
||||
@@ -569,7 +580,6 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
ui->actionFullscreen->setShortcutVisibleInContextMenu(true);
|
||||
ui->actionCtrl_Alt_Del->setShortcutVisibleInContextMenu(true);
|
||||
ui->actionTake_screenshot->setShortcutVisibleInContextMenu(true);
|
||||
#endif
|
||||
@@ -648,6 +658,20 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
} else {
|
||||
ui->actionCursor_Puck->setChecked(true);
|
||||
}
|
||||
|
||||
#ifdef XKBCOMMON
|
||||
# ifdef XKBCOMMON_X11
|
||||
if (QApplication::platformName().contains("xcb"))
|
||||
xkbcommon_x11_init();
|
||||
else
|
||||
# endif
|
||||
# ifdef WAYLAND
|
||||
if (QApplication::platformName().contains("wayland"))
|
||||
xkbcommon_wl_init();
|
||||
else
|
||||
# endif
|
||||
{}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@@ -733,7 +757,9 @@ MainWindow::initRendererMonitorSlot(int monitor_index)
|
||||
secondaryRenderer->showMaximized();
|
||||
}
|
||||
secondaryRenderer->switchRenderer((RendererStack::Renderer) vid_api);
|
||||
secondaryRenderer->setMouseTracking(true);
|
||||
}
|
||||
connect(this, &MainWindow::pollMouse, secondaryRenderer.get(), &RendererStack::mousePoll, Qt::DirectConnection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -880,652 +906,76 @@ MainWindow::on_actionSettings_triggered()
|
||||
plat_pause(currentPause);
|
||||
}
|
||||
|
||||
#if defined(__unix__) && !defined(__HAIKU__)
|
||||
std::array<uint32_t, 256> x11_to_xt_base {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0x01,
|
||||
0x02,
|
||||
0x03,
|
||||
0x04,
|
||||
0x05,
|
||||
0x06,
|
||||
0x07,
|
||||
0x08,
|
||||
0x09,
|
||||
0x0A,
|
||||
0x0B,
|
||||
0x0C,
|
||||
0x0D,
|
||||
0x0E,
|
||||
0x0F,
|
||||
0x10,
|
||||
0x11,
|
||||
0x12,
|
||||
0x13,
|
||||
0x14,
|
||||
0x15,
|
||||
0x16,
|
||||
0x17,
|
||||
0x18,
|
||||
0x19,
|
||||
0x1A,
|
||||
0x1B,
|
||||
0x1C,
|
||||
0x1D,
|
||||
0x1E,
|
||||
0x1F,
|
||||
0x20,
|
||||
0x21,
|
||||
0x22,
|
||||
0x23,
|
||||
0x24,
|
||||
0x25,
|
||||
0x26,
|
||||
0x27,
|
||||
0x28,
|
||||
0x29,
|
||||
0x2A,
|
||||
0x2B,
|
||||
0x2C,
|
||||
0x2D,
|
||||
0x2E,
|
||||
0x2F,
|
||||
0x30,
|
||||
0x31,
|
||||
0x32,
|
||||
0x33,
|
||||
0x34,
|
||||
0x35,
|
||||
0x36,
|
||||
0x37,
|
||||
0x38,
|
||||
0x39,
|
||||
0x3A,
|
||||
0x3B,
|
||||
0x3C,
|
||||
0x3D,
|
||||
0x3E,
|
||||
0x3F,
|
||||
0x40,
|
||||
0x41,
|
||||
0x42,
|
||||
0x43,
|
||||
0x44,
|
||||
0x45,
|
||||
0x46,
|
||||
0x47,
|
||||
0x48,
|
||||
0x49,
|
||||
0x4A,
|
||||
0x4B,
|
||||
0x4C,
|
||||
0x4D,
|
||||
0x4E,
|
||||
0x4F,
|
||||
0x50,
|
||||
0x51,
|
||||
0x52,
|
||||
0x53,
|
||||
0x54,
|
||||
0x55,
|
||||
0x56,
|
||||
0x57,
|
||||
0x58,
|
||||
0x147,
|
||||
0x148,
|
||||
0x149,
|
||||
0,
|
||||
0x14B,
|
||||
0,
|
||||
0x14D,
|
||||
0x14F,
|
||||
0x150,
|
||||
0x151,
|
||||
0x152,
|
||||
0x153,
|
||||
0x11C,
|
||||
0x11D,
|
||||
0, // Pause/Break key.
|
||||
0x137,
|
||||
0x135,
|
||||
0x138,
|
||||
0, // Ditto as above comment.
|
||||
0x15B,
|
||||
0x15C,
|
||||
0x15D,
|
||||
};
|
||||
|
||||
std::array<uint32_t, 256> x11_to_xt_2 {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0x01,
|
||||
0x02,
|
||||
0x03,
|
||||
0x04,
|
||||
0x05,
|
||||
0x06,
|
||||
0x07,
|
||||
0x08,
|
||||
0x09,
|
||||
0x0A,
|
||||
0x0B,
|
||||
0x0C,
|
||||
0x0D,
|
||||
0x0E,
|
||||
0x0F,
|
||||
0x10,
|
||||
0x11,
|
||||
0x12,
|
||||
0x13,
|
||||
0x14,
|
||||
0x15,
|
||||
0x16,
|
||||
0x17,
|
||||
0x18,
|
||||
0x19,
|
||||
0x1A,
|
||||
0x1B,
|
||||
0x1C,
|
||||
0x1D,
|
||||
0x1E,
|
||||
0x1F,
|
||||
0x20,
|
||||
0x21,
|
||||
0x22,
|
||||
0x23,
|
||||
0x24,
|
||||
0x25,
|
||||
0x26,
|
||||
0x27,
|
||||
0x28,
|
||||
0x29,
|
||||
0x2A,
|
||||
0x2B,
|
||||
0x2C,
|
||||
0x2D,
|
||||
0x2E,
|
||||
0x2F,
|
||||
0x30,
|
||||
0x31,
|
||||
0x32,
|
||||
0x33,
|
||||
0x34,
|
||||
0x35,
|
||||
0x36,
|
||||
0x37,
|
||||
0x38,
|
||||
0x39,
|
||||
0x3A,
|
||||
0x3B,
|
||||
0x3C,
|
||||
0x3D,
|
||||
0x3E,
|
||||
0x3F,
|
||||
0x40,
|
||||
0x41,
|
||||
0x42,
|
||||
0x43,
|
||||
0x44,
|
||||
0x45,
|
||||
0x46,
|
||||
0x47,
|
||||
0x48,
|
||||
0x49,
|
||||
0x4A,
|
||||
0x4B,
|
||||
0x4C,
|
||||
0x4D,
|
||||
0x4E,
|
||||
0x4F,
|
||||
0x50,
|
||||
0x51,
|
||||
0x52,
|
||||
0x53,
|
||||
0x138,
|
||||
0x55,
|
||||
0x56,
|
||||
0x57,
|
||||
0x58,
|
||||
0x56,
|
||||
0x70,
|
||||
0x7B,
|
||||
0x7D,
|
||||
0x2B,
|
||||
0x7E,
|
||||
0,
|
||||
0x11C,
|
||||
0x11D,
|
||||
0x135,
|
||||
0x137,
|
||||
0x138,
|
||||
0,
|
||||
0x147,
|
||||
0x148,
|
||||
0x149,
|
||||
0x14B,
|
||||
0x14D,
|
||||
0x14F,
|
||||
0x150,
|
||||
0x151,
|
||||
0x152,
|
||||
0x153,
|
||||
0,
|
||||
0, /* Mute */
|
||||
0, /* Volume Down */
|
||||
0, /* Volume Up */
|
||||
0, /* Power Off */
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0x70,
|
||||
0x7B,
|
||||
0x73,
|
||||
0x15B,
|
||||
0x15C,
|
||||
0x15D
|
||||
};
|
||||
|
||||
std::array<uint32_t, 256> x11_to_xt_vnc {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0x1D,
|
||||
0x11D,
|
||||
0x2A,
|
||||
0x36,
|
||||
0,
|
||||
0,
|
||||
0x38,
|
||||
0x138,
|
||||
0x39,
|
||||
0x0B,
|
||||
0x02,
|
||||
0x03,
|
||||
0x04,
|
||||
0x05,
|
||||
0x06,
|
||||
0x07,
|
||||
0x08,
|
||||
0x09,
|
||||
0x0A,
|
||||
0x0C,
|
||||
0x0D,
|
||||
0x1A,
|
||||
0x1B,
|
||||
0x27,
|
||||
0x28,
|
||||
0x29,
|
||||
0x33,
|
||||
0x34,
|
||||
0x35,
|
||||
0x2B,
|
||||
0x1E,
|
||||
0x30,
|
||||
0x2E,
|
||||
0x20,
|
||||
0x12,
|
||||
0x21,
|
||||
0x22,
|
||||
0x23,
|
||||
0x17,
|
||||
0x24,
|
||||
0x25,
|
||||
0x26,
|
||||
0x32,
|
||||
0x31,
|
||||
0x18,
|
||||
0x19,
|
||||
0x10,
|
||||
0x13,
|
||||
0x1F,
|
||||
0x14,
|
||||
0x16,
|
||||
0x2F,
|
||||
0x11,
|
||||
0x2D,
|
||||
0x15,
|
||||
0x2C,
|
||||
0x0E,
|
||||
0x1C,
|
||||
0x0F,
|
||||
0x01,
|
||||
0x153,
|
||||
0x147,
|
||||
0x14F,
|
||||
0x149,
|
||||
0x151,
|
||||
0x148,
|
||||
0x150,
|
||||
0x14B,
|
||||
0x14D,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
std::array<uint32_t, 256> darwin_to_xt {
|
||||
0x1E,
|
||||
0x1F,
|
||||
0x20,
|
||||
0x21,
|
||||
0x23,
|
||||
0x22,
|
||||
0x2C,
|
||||
0x2D,
|
||||
0x2E,
|
||||
0x2F,
|
||||
0x2B,
|
||||
0x30,
|
||||
0x10,
|
||||
0x11,
|
||||
0x12,
|
||||
0x13,
|
||||
0x15,
|
||||
0x14,
|
||||
0x02,
|
||||
0x03,
|
||||
0x04,
|
||||
0x05,
|
||||
0x07,
|
||||
0x06,
|
||||
0x0D,
|
||||
0x0A,
|
||||
0x08,
|
||||
0x0C,
|
||||
0x09,
|
||||
0x0B,
|
||||
0x1B,
|
||||
0x18,
|
||||
0x16,
|
||||
0x1A,
|
||||
0x17,
|
||||
0x19,
|
||||
0x1C,
|
||||
0x26,
|
||||
0x24,
|
||||
0x28,
|
||||
0x25,
|
||||
0x27,
|
||||
0x2B,
|
||||
0x33,
|
||||
0x35,
|
||||
0x31,
|
||||
0x32,
|
||||
0x34,
|
||||
0x0F,
|
||||
0x39,
|
||||
0x29,
|
||||
0x0E,
|
||||
0x11C,
|
||||
0x01,
|
||||
0x15C,
|
||||
0x15B,
|
||||
0x2A,
|
||||
0x3A,
|
||||
0x38,
|
||||
0x1D,
|
||||
0x36,
|
||||
0x138,
|
||||
0x11D,
|
||||
0x15C,
|
||||
0,
|
||||
0x53,
|
||||
0,
|
||||
0x37,
|
||||
0,
|
||||
0x4E,
|
||||
0,
|
||||
0x45,
|
||||
0x130,
|
||||
0x12E,
|
||||
0x120,
|
||||
0x135,
|
||||
0x11C,
|
||||
0,
|
||||
0x4A,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0x52,
|
||||
0x4F,
|
||||
0x50,
|
||||
0x51,
|
||||
0x4B,
|
||||
0x4C,
|
||||
0x4D,
|
||||
0x47,
|
||||
0,
|
||||
0x48,
|
||||
0x49,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0x3F,
|
||||
0x40,
|
||||
0x41,
|
||||
0x3D,
|
||||
0x42,
|
||||
0x43,
|
||||
0,
|
||||
0x57,
|
||||
0,
|
||||
0x137,
|
||||
0,
|
||||
0x46,
|
||||
0,
|
||||
0x44,
|
||||
0x15D,
|
||||
0x58,
|
||||
0,
|
||||
0, // Pause/Break key.
|
||||
0x152,
|
||||
0x147,
|
||||
0x149,
|
||||
0x153,
|
||||
0x3E,
|
||||
0x14F,
|
||||
0x3C,
|
||||
0x151,
|
||||
0x3B,
|
||||
0x14B,
|
||||
0x14D,
|
||||
0x150,
|
||||
0x148,
|
||||
0,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(__unix__) && !defined(__HAIKU__)
|
||||
static std::unordered_map<uint32_t, uint16_t> evdev_to_xt = {
|
||||
{96, 0x11C},
|
||||
{ 97, 0x11D},
|
||||
{ 98, 0x135},
|
||||
{ 99, 0x71 },
|
||||
{ 100, 0x138},
|
||||
{ 101, 0x1C },
|
||||
{ 102, 0x147},
|
||||
{ 103, 0x148},
|
||||
{ 104, 0x149},
|
||||
{ 105, 0x14B},
|
||||
{ 106, 0x14D},
|
||||
{ 107, 0x14F},
|
||||
{ 108, 0x150},
|
||||
{ 109, 0x151},
|
||||
{ 110, 0x152},
|
||||
{ 111, 0x153}
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef __HAIKU__
|
||||
static std::unordered_map<uint8_t, uint16_t> be_to_xt = {
|
||||
{0x01, 0x01 },
|
||||
{ B_F1_KEY, 0x3B },
|
||||
{ B_F2_KEY, 0x3C },
|
||||
{ B_F3_KEY, 0x3D },
|
||||
{ B_F4_KEY, 0x3E },
|
||||
{ B_F5_KEY, 0x3F },
|
||||
{ B_F6_KEY, 0x40 },
|
||||
{ B_F7_KEY, 0x41 },
|
||||
{ B_F8_KEY, 0x42 },
|
||||
{ B_F9_KEY, 0x43 },
|
||||
{ B_F10_KEY, 0x44 },
|
||||
{ B_F11_KEY, 0x57 },
|
||||
{ B_F12_KEY, 0x58 },
|
||||
{ 0x11, 0x29 },
|
||||
{ 0x12, 0x02 },
|
||||
{ 0x13, 0x03 },
|
||||
{ 0x14, 0x04 },
|
||||
{ 0x15, 0x05 },
|
||||
{ 0x16, 0x06 },
|
||||
{ 0x17, 0x07 },
|
||||
{ 0x18, 0x08 },
|
||||
{ 0x19, 0x09 },
|
||||
{ 0x1A, 0x0A },
|
||||
{ 0x1B, 0x0B },
|
||||
{ 0x1C, 0x0C },
|
||||
{ 0x1D, 0x0D },
|
||||
{ 0x1E, 0x0E },
|
||||
{ 0x1F, 0x152},
|
||||
{ 0x20, 0x147},
|
||||
{ 0x21, 0x149},
|
||||
{ 0x22, 0x45 },
|
||||
{ 0x23, 0x135},
|
||||
{ 0x24, 0x37 },
|
||||
{ 0x25, 0x4A },
|
||||
{ 0x26, 0x0F },
|
||||
{ 0x27, 0x10 },
|
||||
{ 0x28, 0x11 },
|
||||
{ 0x29, 0x12 },
|
||||
{ 0x2A, 0x13 },
|
||||
{ 0x2B, 0x14 },
|
||||
{ 0x2C, 0x15 },
|
||||
{ 0x2D, 0x16 },
|
||||
{ 0x2E, 0x17 },
|
||||
{ 0x2F, 0x18 },
|
||||
{ 0x30, 0x19 },
|
||||
{ 0x31, 0x1A },
|
||||
{ 0x32, 0x1B },
|
||||
{ 0x33, 0x2B },
|
||||
{ 0x34, 0x153},
|
||||
{ 0x35, 0x14F},
|
||||
{ 0x36, 0x151},
|
||||
{ 0x37, 0x47 },
|
||||
{ 0x38, 0x48 },
|
||||
{ 0x39, 0x49 },
|
||||
{ 0x3A, 0x4E },
|
||||
{ 0x3B, 0x3A },
|
||||
{ 0x3C, 0x1E },
|
||||
{ 0x3D, 0x1F },
|
||||
{ 0x3E, 0x20 },
|
||||
{ 0x3F, 0x21 },
|
||||
{ 0x40, 0x22 },
|
||||
{ 0x41, 0x23 },
|
||||
{ 0x42, 0x24 },
|
||||
{ 0x43, 0x25 },
|
||||
{ 0x44, 0x26 },
|
||||
{ 0x45, 0x27 },
|
||||
{ 0x46, 0x28 },
|
||||
{ 0x47, 0x1C },
|
||||
{ 0x48, 0x4B },
|
||||
{ 0x49, 0x4C },
|
||||
{ 0x4A, 0x4D },
|
||||
{ 0x4B, 0x2A },
|
||||
{ 0x4C, 0x2C },
|
||||
{ 0x4D, 0x2D },
|
||||
{ 0x4E, 0x2E },
|
||||
{ 0x4F, 0x2F },
|
||||
{ 0x50, 0x30 },
|
||||
{ 0x51, 0x31 },
|
||||
{ 0x52, 0x32 },
|
||||
{ 0x53, 0x33 },
|
||||
{ 0x54, 0x34 },
|
||||
{ 0x55, 0x35 },
|
||||
{ 0x56, 0x36 },
|
||||
{ 0x57, 0x148},
|
||||
{ 0x58, 0x51 },
|
||||
{ 0x59, 0x50 },
|
||||
{ 0x5A, 0x4F },
|
||||
{ 0x5B, 0x11C},
|
||||
{ 0x5C, 0x1D },
|
||||
{ 0x5D, 0x38 },
|
||||
{ 0x5E, 0x39 },
|
||||
{ 0x5F, 0x138},
|
||||
{ 0x60, 0x11D},
|
||||
{ 0x61, 0x14B},
|
||||
{ 0x62, 0x150},
|
||||
{ 0x63, 0x14D},
|
||||
{ 0x64, 0x52 },
|
||||
{ 0x65, 0x53 },
|
||||
|
||||
{ 0x0e, 0x137},
|
||||
{ 0x0f, 0x46 },
|
||||
{ 0x66, 0x15B},
|
||||
{ 0x67, 0x15C},
|
||||
{ 0x68, 0x15D},
|
||||
{ 0x69, 0x56 }
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(__unix__) && !defined(__HAIKU__)
|
||||
static std::array<uint32_t, 256> &selected_keycode = x11_to_xt_base;
|
||||
#endif
|
||||
|
||||
uint16_t
|
||||
x11_keycode_to_keysym(uint32_t keycode)
|
||||
void
|
||||
MainWindow::processKeyboardInput(bool down, uint32_t keycode)
|
||||
{
|
||||
uint16_t finalkeycode = 0;
|
||||
#if defined(Q_OS_WINDOWS)
|
||||
finalkeycode = (keycode & 0xFFFF);
|
||||
#if defined(Q_OS_WINDOWS) /* non-raw input */
|
||||
keycode &= 0xffff;
|
||||
#elif defined(Q_OS_MACOS)
|
||||
finalkeycode = darwin_to_xt[keycode];
|
||||
keycode = (keycode < 127) ? cocoa_keycodes[keycode] : 0;
|
||||
#elif defined(__HAIKU__)
|
||||
finalkeycode = be_to_xt[keycode];
|
||||
keycode = be_keycodes[keycode];
|
||||
#else
|
||||
static Display *x11display = nullptr;
|
||||
if (QApplication::platformName().contains("wayland")) {
|
||||
selected_keycode = x11_to_xt_2;
|
||||
} else if (QApplication::platformName().contains("eglfs")) {
|
||||
keycode -= 8;
|
||||
if (keycode <= 88)
|
||||
finalkeycode = keycode;
|
||||
else
|
||||
finalkeycode = evdev_to_xt[keycode];
|
||||
} else if (!x11display) {
|
||||
x11display = XOpenDisplay(nullptr);
|
||||
if (XKeysymToKeycode(x11display, XK_Home) == 110) {
|
||||
selected_keycode = x11_to_xt_2;
|
||||
} else if (XKeysymToKeycode(x11display, XK_Home) == 69) {
|
||||
selected_keycode = x11_to_xt_vnc;
|
||||
}
|
||||
}
|
||||
if (!QApplication::platformName().contains("eglfs"))
|
||||
finalkeycode = selected_keycode[keycode];
|
||||
# ifdef XKBCOMMON
|
||||
if (xkbcommon_keymap)
|
||||
keycode = xkbcommon_translate(keycode);
|
||||
else
|
||||
# endif
|
||||
# ifdef EVDEV_KEYBOARD_HPP
|
||||
keycode = evdev_translate(keycode - 8);
|
||||
# else
|
||||
keycode = 0;
|
||||
# endif
|
||||
#endif
|
||||
if (rctrl_is_lalt && finalkeycode == 0x11D) {
|
||||
finalkeycode = 0x38;
|
||||
|
||||
/* Apply special cases. */
|
||||
switch (keycode) {
|
||||
case 0x54: /* Alt + Print Screen (special case, i.e. evdev SELECTIVE_SCREENSHOT) */
|
||||
/* Send Alt as well. */
|
||||
if (down) {
|
||||
keyboard_input(down, 0x38);
|
||||
} else {
|
||||
keyboard_input(down, keycode);
|
||||
keycode = 0x38;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x10b: /* Microsoft scroll up normal */
|
||||
case 0x18b: /* Microsoft scroll down normal */
|
||||
/* This abuses make/break codes. Send them manually, only on press. */
|
||||
if (down) {
|
||||
keyboard_send(0xe0);
|
||||
keyboard_send(keycode & 0xff);
|
||||
}
|
||||
return;
|
||||
|
||||
case 0x11d: /* Right Ctrl */
|
||||
if (rctrl_is_lalt)
|
||||
keycode = 0x38; /* map to Left Alt */
|
||||
break;
|
||||
|
||||
case 0x137: /* Print Screen */
|
||||
if (keyboard_recv(0x38) || keyboard_recv(0x138)) { /* Alt+ */
|
||||
keycode = 0x54;
|
||||
} else if (down) {
|
||||
keyboard_input(down, 0x12a);
|
||||
} else {
|
||||
keyboard_input(down, keycode);
|
||||
keycode = 0x12a;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x145: /* Pause */
|
||||
if (keyboard_recv(0x1d) || keyboard_recv(0x11d)) { /* Ctrl+ */
|
||||
keycode = 0x146;
|
||||
} else {
|
||||
keyboard_input(down, 0xe11d);
|
||||
keycode &= 0x00ff;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return finalkeycode;
|
||||
|
||||
keyboard_input(down, keycode);
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
@@ -1543,6 +993,7 @@ static std::unordered_map<uint32_t, uint16_t> mac_modifiers_to_xt = {
|
||||
{ NX_DEVICE_ALPHASHIFT_STATELESS_MASK, 0x3A },
|
||||
{ NX_DEVICERCTLKEYMASK, 0x11D},
|
||||
};
|
||||
static bool mac_iso_swap = false;
|
||||
|
||||
void
|
||||
MainWindow::processMacKeyboardInput(bool down, const QKeyEvent *event)
|
||||
@@ -1583,11 +1034,62 @@ MainWindow::processMacKeyboardInput(bool down, const QKeyEvent *event)
|
||||
// It's possible that other lock keys get delivered in this way, but
|
||||
// standard Apple keyboards don't have them, so this is untested.
|
||||
if (event->key() == Qt::Key_CapsLock) {
|
||||
keyboard_input(1, 0x3A);
|
||||
keyboard_input(0, 0x3A);
|
||||
keyboard_input(1, 0x3a);
|
||||
keyboard_input(0, 0x3a);
|
||||
}
|
||||
} else {
|
||||
keyboard_input(down, x11_keycode_to_keysym(event->nativeVirtualKey()));
|
||||
/* Apple ISO keyboards are notorious for swapping ISO_Section and ANSI_Grave
|
||||
on *some* layouts and/or models. While macOS can sort this mess out at
|
||||
keymap level, it still provides applications with unfiltered, ambiguous
|
||||
keycodes, so we have to disambiguate them by making some bold assumptions
|
||||
about the user's keyboard layout based on the OS-provided key mappings. */
|
||||
auto nvk = event->nativeVirtualKey();
|
||||
if ((nvk == 0x0a) || (nvk == 0x32)) {
|
||||
/* Flaws:
|
||||
- Layouts with `~ on ISO_Section are partially detected due to a conflict with ANSI
|
||||
- Czech and Slovak are not detected as they have <> ANSI_Grave and \| ISO_Section (differing from PC actually)
|
||||
- Italian is partially detected due to \| conflicting with Brazilian
|
||||
- Romanian third level ANSI_Grave is unknown
|
||||
- Russian clusters <>, plusminus and paragraph into a four-level ANSI_Grave, with the aforementioned `~ on ISO_Section */
|
||||
auto key = event->key();
|
||||
if ((nvk == 0x32) && ( /* system reports ANSI_Grave for ISO_Section keys: */
|
||||
(key == Qt::Key_Less) || (key == Qt::Key_Greater) || /* Croatian, French, German, Icelandic, Italian, Norwegian, Portuguese, Spanish, Spanish Latin America, Turkish Q */
|
||||
(key == Qt::Key_Ugrave) || /* French Canadian */
|
||||
(key == Qt::Key_Icircumflex) || /* Romanian */
|
||||
(key == Qt::Key_Iacute) || /* Hungarian */
|
||||
(key == Qt::Key_BracketLeft) || (key == Qt::Key_BracketRight) || /* Russian upper two levels */
|
||||
(key == Qt::Key_W) /* Turkish F */
|
||||
))
|
||||
mac_iso_swap = true;
|
||||
else if ((nvk == 0x0a) && ( /* system reports ISO_Section for ANSI_Grave keys: */
|
||||
(key == Qt::Key_paragraph) || (key == Qt::Key_plusminus) || /* Arabic, British, Bulgarian, Danish shifted, Dutch, Greek, Hebrew, Hungarian shifted, International English, Norwegian shifted, Portuguese, Russian lower two levels, Swiss unshifted, Swedish unshifted, Turkish F */
|
||||
(key == Qt::Key_At) || (key == Qt::Key_NumberSign) || /* Belgian, French */
|
||||
(key == Qt::Key_Apostrophe) || /* Brazilian unshifted */
|
||||
(key == Qt::Key_QuoteDbl) || /* Brazilian shifted, Turkish Q unshifted */
|
||||
(key == Qt::Key_QuoteLeft) || /* Croatian (right quote unknown) */
|
||||
(key == Qt::Key_Dollar) || /* Danish unshifted */
|
||||
(key == Qt::Key_AsciiCircum) || (key == 0x1ffffff) || /* German unshifted (0x1ffffff according to one tester), Polish unshifted */
|
||||
(key == Qt::Key_degree) || /* German shifted, Icelandic unshifted, Spanish Latin America shifted, Swiss shifted, Swedish shifted */
|
||||
(key == Qt::Key_0) || /* Hungarian unshifted */
|
||||
(key == Qt::Key_diaeresis) || /* Icelandic shifted */
|
||||
(key == Qt::Key_acute) || /* Norwegian unshifted */
|
||||
(key == Qt::Key_Asterisk) || /* Polish shifted */
|
||||
(key == Qt::Key_masculine) || (key == Qt::Key_ordfeminine) || /* Spanish (masculine unconfirmed) */
|
||||
(key == Qt::Key_Eacute) || /* Turkish Q shifted */
|
||||
(key == Qt::Key_Slash) /* French Canadian unshifted, Ukrainian shifted */
|
||||
))
|
||||
mac_iso_swap = true;
|
||||
#if 0
|
||||
if (down) {
|
||||
QMessageBox questionbox(QMessageBox::Icon::Information, QString("Mac key swap test"), QString("nativeVirtualKey 0x%1\nnativeScanCode 0x%2\nkey 0x%3\nmac_iso_swap %4").arg(nvk, 0, 16).arg(event->nativeScanCode(), 0, 16).arg(key, 0, 16).arg(mac_iso_swap ? "yes" : "no"), QMessageBox::Ok, this);
|
||||
questionbox.exec();
|
||||
}
|
||||
#endif
|
||||
if (mac_iso_swap)
|
||||
nvk = (nvk == 0x0a) ? 0x32 : 0x0a;
|
||||
}
|
||||
|
||||
processKeyboardInput(down, nvk);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1731,33 +1233,21 @@ void
|
||||
MainWindow::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (send_keyboard_input && !(kbd_req_capture && !mouse_capture)) {
|
||||
// Windows keys in Qt have one-to-one mapping.
|
||||
if (event->key() == Qt::Key_Pause && !keyboard_recv(0x38) && !keyboard_recv(0x138)) {
|
||||
if ((keyboard_recv(0x1D) || keyboard_recv(0x11D))) {
|
||||
keyboard_input(1, 0x46);
|
||||
} else {
|
||||
keyboard_input(0, 0xE1);
|
||||
keyboard_input(0, 0x1D);
|
||||
keyboard_input(0, 0x45);
|
||||
keyboard_input(0, 0xE1);
|
||||
keyboard_input(1, 0x1D);
|
||||
keyboard_input(1, 0x45);
|
||||
}
|
||||
} else
|
||||
#ifdef Q_OS_MACOS
|
||||
processMacKeyboardInput(true, event);
|
||||
processMacKeyboardInput(true, event);
|
||||
#else
|
||||
keyboard_input(1, x11_keycode_to_keysym(event->nativeScanCode()));
|
||||
processKeyboardInput(true, event->nativeScanCode());
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((video_fullscreen > 0) && keyboard_isfsexit()) {
|
||||
ui->actionFullscreen->trigger();
|
||||
}
|
||||
if (!fs_off_signal && (video_fullscreen > 0) && keyboard_isfsexit())
|
||||
fs_off_signal = true;
|
||||
|
||||
if (keyboard_ismsexit()) {
|
||||
if (!fs_on_signal && (video_fullscreen == 0) && keyboard_isfsenter())
|
||||
fs_on_signal = true;
|
||||
|
||||
if (keyboard_ismsexit())
|
||||
plat_mouse_capture(0);
|
||||
}
|
||||
|
||||
if ((video_fullscreen > 0) && (keyboard_recv(0x1D) || keyboard_recv(0x11D))) {
|
||||
if (keyboard_recv(0x57))
|
||||
@@ -1789,13 +1279,24 @@ MainWindow::keyReleaseEvent(QKeyEvent *event)
|
||||
plat_pause(dopause ^ 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (fs_off_signal && (video_fullscreen > 0) && keyboard_isfsexit_down()) {
|
||||
ui->actionFullscreen->trigger();
|
||||
fs_off_signal = false;
|
||||
}
|
||||
|
||||
if (fs_on_signal && (video_fullscreen == 0) && keyboard_isfsenter_down()) {
|
||||
ui->actionFullscreen->trigger();
|
||||
fs_on_signal = false;
|
||||
}
|
||||
|
||||
if (!send_keyboard_input)
|
||||
return;
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
processMacKeyboardInput(false, event);
|
||||
#else
|
||||
keyboard_input(0, x11_keycode_to_keysym(event->nativeScanCode()));
|
||||
processKeyboardInput(false, event->nativeScanCode());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -155,6 +155,7 @@ private:
|
||||
std::unique_ptr<MachineStatus> status;
|
||||
std::shared_ptr<MediaMenu> mm;
|
||||
|
||||
void processKeyboardInput(bool down, uint32_t keycode);
|
||||
#ifdef Q_OS_MACOS
|
||||
uint32_t last_modifiers = 0;
|
||||
void processMacKeyboardInput(bool down, const QKeyEvent *event);
|
||||
@@ -166,6 +167,10 @@ private:
|
||||
bool resizableonce = false;
|
||||
bool vnc_enabled = false;
|
||||
|
||||
/* Full screen ON and OFF signals */
|
||||
bool fs_on_signal = false;
|
||||
bool fs_off_signal = false;
|
||||
|
||||
friend class SpecifyDimensions;
|
||||
friend class ProgSettings;
|
||||
friend class RendererCommon;
|
||||
|
||||
@@ -362,12 +362,6 @@
|
||||
<property name="text">
|
||||
<string>&Fullscreen</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Alt+PgUp</string>
|
||||
</property>
|
||||
<property name="shortcutVisibleInContextMenu">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSoftware_Renderer">
|
||||
<property name="checkable">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user