diff --git a/.github/workflows/cmake_linux.yml b/.github/workflows/cmake_linux.yml index 5dc0387d8..3fb8b0d61 100644 --- a/.github/workflows/cmake_linux.yml +++ b/.github/workflows/cmake_linux.yml @@ -55,6 +55,7 @@ jobs: - name: SDL GUI qt: off qt6: off + slug: -SDL static: on - name: Qt 5 GUI qt: on @@ -121,10 +122,9 @@ jobs: - name: Configure CMake run: >- - cmake -G Ninja -S . -B build --preset ${{ matrix.build.preset }} - --toolchain ${{ matrix.environment.toolchain }} + cmake -S . -B build --preset ${{ matrix.build.preset }} + --toolchain ${{ matrix.environment.toolchain }} -D NEW_DYNAREC=${{ matrix.dynarec.new }} - -D CMAKE_INSTALL_PREFIX=./build/artifacts -D QT=${{ matrix.ui.qt }} -D USE_QT6=${{ matrix.ui.qt6 }} diff --git a/.github/workflows/cmake_macos.yml b/.github/workflows/cmake_macos.yml index c917932fe..ace5314c8 100644 --- a/.github/workflows/cmake_macos.yml +++ b/.github/workflows/cmake_macos.yml @@ -26,11 +26,11 @@ on: jobs: - macos13-x86_64: + macos: - name: "${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, x86_64" + name: "${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, ${{ matrix.environment.arch }}" - runs-on: macos-13 + runs-on: ${{ matrix.environment.runner }} strategy: fail-fast: true @@ -54,12 +54,27 @@ jobs: ui: - name: SDL GUI qt: off + slug: -SDL static: on - - name: Qt GUI + - name: Qt 5 GUI qt: on - slug: -Qt + slug: -Qt5 packages: >- qt@5 + environment: + - arch: x86_64 + toolchain: ./cmake/flags-gcc-x86_64.cmake + slug: -x86_64 + runner: macos-13 + - arch: arm64 + toolchain: ./cmake/llvm-macos-aarch64.cmake + slug: -arm64 + runner: macos-14 + exclude: + - dynarec: + new: off + environment: + arch: arm64 steps: - name: Install dependencies @@ -81,10 +96,9 @@ jobs: - name: Configure CMake run: >- - cmake -G Ninja -S . -B build --preset ${{ matrix.build.preset }} - --toolchain ./cmake/flags-gcc-x86_64.cmake + cmake -S . -B build --preset ${{ matrix.build.preset }} + --toolchain ${{ matrix.environment.toolchain }} -D NEW_DYNAREC=${{ matrix.dynarec.new }} - -D CMAKE_INSTALL_PREFIX=./build/artifacts -D QT=${{ matrix.ui.qt }} -D Qt5_ROOT=$(brew --prefix qt@5) -D Qt5LinguistTools_ROOT=$(brew --prefix qt@5) @@ -100,82 +114,5 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v4 with: - name: '86Box${{ matrix.ui.slug }}${{ matrix.dynarec.slug }}${{ matrix.build.slug }}-macOS-x86_64-gha${{ github.run_number }}' - path: build/artifacts/** - - macos14-arm64: - - name: "${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, arm64" - - runs-on: macos-14 - - strategy: - fail-fast: true - matrix: - build: -# - name: Regular -# preset: regular - - name: Debug - preset: dev_debug - slug: -Debug - - name: Dev - preset: development - slug: -Dev - dynarec: -# - name: ODR -# new: off -# slug: -ODR - - name: NDR - new: on - slug: -NDR - ui: - - name: SDL GUI - qt: off - static: on - - name: Qt GUI - qt: on - slug: -Qt - packages: >- - qt@5 - - steps: - - name: Install dependencies - run: >- - brew install - sdl2 - rtmidi - openal-soft - fluidsynth - libslirp - vde - libserialport - ${{ matrix.ui.packages }} - - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - - - name: Configure CMake - run: >- - cmake -G Ninja -S . -B build --preset ${{ matrix.build.preset }} - --toolchain ./cmake/llvm-macos-aarch64.cmake - -D NEW_DYNAREC=${{ matrix.dynarec.new }} - -D CMAKE_INSTALL_PREFIX=./build/artifacts - -D QT=${{ matrix.ui.qt }} - -D Qt5_ROOT=$(brew --prefix qt@5) - -D Qt5LinguistTools_ROOT=$(brew --prefix qt@5) - -D OpenAL_ROOT=$(brew --prefix openal-soft) - -D LIBSERIALPORT_ROOT=$(brew --prefix libserialport) - - - name: Build - run: cmake --build build - - - name: Generate package - run: cmake --install build - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: '86Box${{ matrix.ui.slug }}${{ matrix.dynarec.slug }}${{ matrix.build.slug }}-macOS-arm64-gha${{ github.run_number }}' + name: '86Box${{ matrix.ui.slug }}${{ matrix.dynarec.slug }}${{ matrix.build.slug }}-macOS${{ matrix.environment.slug }}-gha${{ github.run_number }}' path: build/artifacts/** diff --git a/.github/workflows/cmake_windows_msys2.yml b/.github/workflows/cmake_windows_msys2.yml index eb83d4674..8959395eb 100644 --- a/.github/workflows/cmake_windows_msys2.yml +++ b/.github/workflows/cmake_windows_msys2.yml @@ -1,4 +1,4 @@ -name: CMake (Windows, msys2) +name: CMake (Windows) on: @@ -26,9 +26,9 @@ on: jobs: - msys2: + windows: - name: "${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, ${{ matrix.environment.msystem }}" + name: "${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, ${{ matrix.environment.msystem }}" runs-on: ${{ matrix.environment.runner }} @@ -56,14 +56,15 @@ jobs: new: on slug: -NDR ui: - - name: Qt GUI + - name: Qt 5 GUI qt: on + slug: -Qt5 static: on - slug: -Qt packages: >- - qt5-base:p - qt5-tools:p + qt5-static:p vulkan-headers:p +# qt5-base:p +# qt5-tools:p environment: # - msystem: MSYS # toolchain: ./cmake/flags-gcc-x86_64.cmake @@ -77,10 +78,12 @@ jobs: # prefix: mingw-w64-clang-x86_64 # toolchain: ./cmake/llvm-win32-x86_64.cmake # slug: "CLANG64" +# runner: windows-2022 # - msystem: UCRT64 # prefix: mingw-w64-ucrt-x86_64 # toolchain: ./cmake/flags-gcc-x86_64.cmake # slug: "UCRT64" +# runner: windows-2022 - msystem: CLANGARM64 toolchain: ./cmake/flags-gcc-aarch64.cmake slug: -arm64 @@ -112,8 +115,7 @@ jobs: libslirp:p fluidsynth:p libserialport:p - qt5-static:p - vulkan-headers:p + ${{ matrix.ui.packages }} openmp:p - name: Checkout repository @@ -123,10 +125,10 @@ jobs: - name: Configure CMake run: >- - cmake -G Ninja -S . -B build --preset ${{ matrix.build.preset }} + cmake -S . -B build --preset ${{ matrix.build.preset }} --toolchain ${{ matrix.environment.toolchain }} -D NEW_DYNAREC=${{ matrix.dynarec.new }} - -D CMAKE_INSTALL_PREFIX=./build/artifacts + -D QT=${{ matrix.ui.qt }} - name: Build run: cmake --build build diff --git a/.github/workflows/codeql_linux.yml b/.github/workflows/codeql_linux.yml index b8fb93ef6..957c7090b 100644 --- a/.github/workflows/codeql_linux.yml +++ b/.github/workflows/codeql_linux.yml @@ -33,7 +33,7 @@ jobs: analyze-linux: - name: "Analyze (${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, x86_64)" + name: "${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, ${{ matrix.environment.arch }}" runs-on: ubuntu-22.04 @@ -68,10 +68,13 @@ jobs: ui: - name: SDL GUI qt: off + qt6: off + slug: -SDL static: on - - name: Qt GUI + - name: Qt 5 GUI qt: on - slug: -Qt + qt6: off + slug: -Qt5 packages: >- qtbase5-dev qtbase5-private-dev @@ -79,6 +82,20 @@ jobs: qttranslations5-l10n libevdev-dev libxkbcommon-x11-dev + environment: + - arch: x86_64 + toolchain: ./cmake/flags-gcc-x86_64.cmake + slug: "-x86_64" + runner: ubuntu-22.04 +# - arch: arm64 +# toolchain: ./cmake/flags-gcc-aarch64.cmake +# slug: -arm64 +# runner: ubuntu-22.04-arm +# exclude: +# - dynarec: +# new: off +# environment: +# arch: arm64 steps: - name: Install dependencies @@ -114,11 +131,11 @@ jobs: - name: Configure CMake run: >- - cmake -G Ninja -S . -B build --preset ${{ matrix.build.preset }} - --toolchain ./cmake/flags-gcc-x86_64.cmake + cmake -S . -B build --preset ${{ matrix.build.preset }} + --toolchain ${{ matrix.environment.toolchain }} -D NEW_DYNAREC=${{ matrix.dynarec.new }} - -D CMAKE_INSTALL_PREFIX=./build/artifacts -D QT=${{ matrix.ui.qt }} + -D USE_QT6=${{ matrix.ui.qt6 }} - name: Build run: | @@ -140,4 +157,4 @@ jobs: with: # Consult https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/scanners/sonarscanner/ for more information and options args: > - --define sonar.cfamily.compile-commands="${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" + --define sonar.cfamily.compile-commands=build/compile_commands.json diff --git a/.github/workflows/codeql_macos.yml b/.github/workflows/codeql_macos.yml index 203f385ff..488cbfd49 100644 --- a/.github/workflows/codeql_macos.yml +++ b/.github/workflows/codeql_macos.yml @@ -31,11 +31,11 @@ on: jobs: - analyze-macos13-x86_64: + analyze-macos: - name: "Analyze (${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, x86_64)" + name: "${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, ${{ matrix.environment.arch }}" - runs-on: macos-13 + runs-on: ${{ matrix.environment.runner }} env: BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed @@ -66,13 +66,29 @@ jobs: new: on slug: -NDR ui: - - name: SDL GUI - qt: off - - name: Qt GUI +# - name: SDL GUI +# qt: off +# slug: -SDL +# static: on + - name: Qt 5 GUI qt: on - slug: -Qt + slug: -Qt5 packages: >- qt@5 + environment: + - arch: x86_64 + toolchain: ./cmake/flags-gcc-x86_64.cmake + slug: -x86_64 + runner: macos-13 +# - arch: arm64 +# toolchain: ./cmake/llvm-macos-aarch64.cmake +# slug: -arm64 +# runner: macos-14 +# exclude: +# - dynarec: +# new: off +# environment: +# arch: arm64 steps: - name: Install dependencies @@ -103,10 +119,9 @@ jobs: - name: Configure CMake run: >- - cmake -G Ninja -S . -B build --preset ${{ matrix.build.preset }} - --toolchain ./cmake/flags-gcc-x86_64.cmake + cmake -S . -B build --preset ${{ matrix.build.preset }} + --toolchain ${{ matrix.environment.toolchain }} -D NEW_DYNAREC=${{ matrix.dynarec.new }} - -D CMAKE_INSTALL_PREFIX=./build/artifacts -D QT=${{ matrix.ui.qt }} -D Qt5_ROOT=$(brew --prefix qt@5) -D Qt5LinguistTools_ROOT=$(brew --prefix qt@5) @@ -133,4 +148,4 @@ jobs: with: # Consult https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/scanners/sonarscanner/ for more information and options args: > - --define sonar.cfamily.compile-commands="${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" + --define sonar.cfamily.compile-commands=build/compile_commands.json diff --git a/.github/workflows/codeql_windows_msys2.yml b/.github/workflows/codeql_windows_msys2.yml index c7edae77f..d70c6fd5f 100644 --- a/.github/workflows/codeql_windows_msys2.yml +++ b/.github/workflows/codeql_windows_msys2.yml @@ -1,4 +1,4 @@ -name: CodeQL Analysis (Windows, msys2) +name: CodeQL Analysis (Windows) on: @@ -31,9 +31,9 @@ on: jobs: - analyze-msys2: + analyze-windows: - name: "Analyze (${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, ${{ matrix.environment.msystem }})" + name: "${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, ${{ matrix.environment.msystem }}" runs-on: ${{ matrix.environment.runner }} @@ -70,14 +70,15 @@ jobs: new: on slug: -NDR ui: - - name: Qt GUI + - name: Qt 5 GUI qt: on + slug: -Qt5 static: off - slug: -Qt packages: >- qt5-base:p qt5-tools:p vulkan-headers:p +# qt5-static:p environment: # - msystem: MSYS # toolchain: ./cmake/flags-gcc-x86_64.cmake @@ -147,10 +148,9 @@ jobs: - name: Configure CMake run: >- - cmake -G Ninja -S . -B build --preset ${{ matrix.build.preset }} + cmake -S . -B build --preset ${{ matrix.build.preset }} --toolchain ${{ matrix.environment.toolchain }} -D NEW_DYNAREC=${{ matrix.dynarec.new }} - -D CMAKE_INSTALL_PREFIX=./build/artifacts -D QT=${{ matrix.ui.qt }} -D STATIC_BUILD=${{ matrix.ui.static }} @@ -177,4 +177,4 @@ jobs: with: # Consult https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/scanners/sonarscanner/ for more information and options args: > - --define sonar.cfamily.compile-commands="${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" + --define sonar.cfamily.compile-commands=build/compile_commands.json diff --git a/CMakeLists.txt b/CMakeLists.txt index 57e3b178f..29fedd6ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -185,6 +185,7 @@ cmake_dependent_option(SIO_DETECT "Super I/O Detection Helper" cmake_dependent_option(WACOM "Wacom Input Devices" ON "DEV_BRANCH" OFF) cmake_dependent_option(XL24 "ATI VGA Wonder XL24 (ATI-28800-6)" ON "DEV_BRANCH" OFF) cmake_dependent_option(NETSWITCH "Network Switch Support" ON "DEV_BRANCH" OFF) +cmake_dependent_option(VFIO "Virtual Function I/O" ON "DEV_BRANCH" OFF) # Ditto but for Qt if(QT) diff --git a/sonar-project.properties b/sonar-project.properties index 781fad035..34cb02b6b 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,12 +1,16 @@ sonar.projectKey=86Box_86Box + sonar.organization=86box # This is the name and version displayed in the SonarCloud UI. -#sonar.projectName=86Box +sonar.projectName=86Box + #sonar.projectVersion=1.0 -# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. +# Path is relative to the sonar-project.properties file. Defaults to . #sonar.sources=. # Encoding of the source code. Default is default system encoding #sonar.sourceEncoding=UTF-8 + +sonar.cfamily.compile-commands=build/compile_commands.json diff --git a/src/86box.c b/src/86box.c index 186b7cba8..591772458 100644 --- a/src/86box.c +++ b/src/86box.c @@ -107,6 +107,7 @@ #include <86box/apm.h> #include <86box/acpi.h> #include <86box/nv/vid_nv_rivatimer.h> +#include <86box/vfio.h> // Disable c99-designator to avoid the warnings about int ng #ifdef __clang__ @@ -1647,6 +1648,11 @@ pc_reset_hard_init(void) the chances of the SCSI controller ending up on the bridge. */ video_voodoo_init(); +#if defined(USE_VFIO) && defined(__linux__) + /* Initialize VFIO */ + vfio_init(); +#endif + /* installs first game port if no device provides one, must be late */ if (joystick_type[0]) gameport_update_joystick_type(0); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 166320061..7c389c368 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -103,6 +103,16 @@ if(VNC) endif() endif() +if(CMAKE_SYSTEM_NAME MATCHES "Linux") + if(VFIO) + include(CheckIncludeFile) + check_include_file("linux/vfio.h" VFIO_AVAILABLE) + if(VFIO_AVAILABLE) + add_compile_definitions(USE_VFIO) + endif() + endif() +endif() + if(INSTRUMENT) add_compile_definitions(USE_INSTRUMENT) endif() diff --git a/src/acpi.c b/src/acpi.c index 411662e39..84d910163 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -8,8 +8,6 @@ * * ACPI emulation. * - * - * * Authors: Miran Grca, * * Copyright 2020 Miran Grca. @@ -1222,7 +1220,7 @@ acpi_reg_write_intel(int size, uint16_t addr, uint8_t val, void *priv) /* GPOREG - General Purpose Output Register (IO) */ if (size == 1) { dev->regs.gporeg[addr & 3] = val; - if ((addr == 0x34) && !strcmp(machine_get_internal_name(), "cubx")) + if ((addr == 0x34) && (machines[machine].init == machine_at_cubx_init)) hdc_onboard_enabled = (val & 0x01); } break; @@ -1749,7 +1747,7 @@ acpi_reg_write_sis_5595(int size, uint16_t addr, uint8_t val, void *priv) break; case 0x1c: dev->regs.gpe_pin = ((dev->regs.gpe_pin & ~(0xff << shift32)) | ((val & 0xff) << shift32)); - if (!strcmp(machine_get_internal_name(), "m747") && (val & 0x10) && + if ((machines[machine].init == machine_at_m747_init) && (val & 0x10) && !(dev->regs.gpe_io & 0x00000010)) resetx86(); break; @@ -2365,7 +2363,7 @@ acpi_reset(void *priv) /* PC Chips M773: - Bit 3: 80-conductor cable on unknown IDE channel (active low) - Bit 1: 80-conductor cable on unknown IDE channel (active low) */ - dev->regs.gpireg[0] = !strcmp(machine_get_internal_name(), "m773") ? 0xf5 : 0xff; + dev->regs.gpireg[0] = (machines[machine].init == machine_at_m773_init) ? 0xf5 : 0xff; dev->regs.gpireg[1] = 0xff; /* A-Trend ATC7020BXII: - Bit 3: 80-conductor cable on secondary IDE channel (active low) @@ -2399,9 +2397,9 @@ acpi_reset(void *priv) - Bit 19: password cleared (active low). */ dev->regs.gpi_val = 0xfff57fc1; - if (!strcmp(machine_get_internal_name(), "ficva503a") || !strcmp(machine_get_internal_name(), "6via90ap")) + if ((machines[machine].init == machine_at_ficva503a_init) || (machines[machine].init == machine_at_6via90ap_init)) dev->regs.gpi_val |= 0x00000004; - else if (!strcmp(machine_get_internal_name(), "ficka6130")) + else if ((machines[machine].init == machine_at_ficka6130_init)) dev->regs.gpi_val |= 0x00080000; /* TriGem Delhi-III second GPI word: @@ -2409,7 +2407,7 @@ acpi_reset(void *priv) - Bit 6 = Password jumper (must be set); - Bit 5 = Enable Setup (must be set). */ - else if (!strcmp(machine_get_internal_name(), "delhi3")) + else if (machines[machine].init == machine_at_delhi3_init) dev->regs.gpi_val |= 0x00008000; } @@ -2420,7 +2418,7 @@ acpi_reset(void *priv) } /* The Gateway Tomahawk requires the LID polarity bit to be set. */ - if (!strcmp(machine_get_internal_name(), "tomahawk")) + if (machines[machine].init == machine_at_tomahawk_init) dev->regs.glbctl |= 0x02000000; acpi_rtc_status = 0; diff --git a/src/apm.c b/src/apm.c index 3973f2b23..b4806cb71 100644 --- a/src/apm.c +++ b/src/apm.c @@ -8,8 +8,6 @@ * * Advanced Power Management emulation. * - * - * * Authors: Miran Grca, * * Copyright 2019 Miran Grca. diff --git a/src/arch_detect.c b/src/arch_detect.c index 4ef267c94..08b92a546 100644 --- a/src/arch_detect.c +++ b/src/arch_detect.c @@ -8,8 +8,6 @@ * * Configure-time architecture detection for the CMake build. * - * - * * Authors: David Hrdlička, * * Copyright 2020-2021 David Hrdlička. diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 6dd95b5dd..3b7eaeb3f 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -8,8 +8,6 @@ * * Generic CD-ROM drive core. * - * - * * Authors: Miran Grca, * * Copyright 2018-2021 Miran Grca. diff --git a/src/cdrom/cdrom_image_viso.c b/src/cdrom/cdrom_image_viso.c index 3eec6d5a1..5c47b745d 100644 --- a/src/cdrom/cdrom_image_viso.c +++ b/src/cdrom/cdrom_image_viso.c @@ -880,7 +880,7 @@ viso_init(const uint8_t id, const char *dirname, int *error) if (dirp) { /* create empty directory if opendir failed */ while ((readdir_entry = readdir(dirp))) { /* Ignore . and .. pseudo-directories. */ - if ((readdir_entry->d_name[0] == '.') && ((readdir_entry->d_name[1] == '\0') || (*((uint16_t *) &readdir_entry->d_name[1]) == '.'))) + if ((readdir_entry->d_name[0] == '.') && ((readdir_entry->d_name[1] == '\0') || (AS_U16(readdir_entry->d_name[1]) == '.'))) continue; children_count++; } @@ -927,7 +927,7 @@ viso_init(const uint8_t id, const char *dirname, int *error) /* Ignore . and .. pseudo-directories. */ if ((readdir_entry->d_name[0] == '.') && ((readdir_entry->d_name[1] == '\0') || - (*((uint16_t *) &readdir_entry->d_name[1]) == '.'))) + (AS_U16(readdir_entry->d_name[1]) == '.'))) continue; /* Add and fill entry. */ @@ -1245,8 +1245,8 @@ next_dir: /* Calculate checksum. */ uint16_t eltorito_checksum = 0; for (int i = 0; i < (p - data); i += 2) - eltorito_checksum -= le16_to_cpu(*((uint16_t *) &data[i])); - *((uint16_t *) &data[28]) = cpu_to_le16(eltorito_checksum); + eltorito_checksum -= le16_to_cpu(AS_U16(data[i])); + AS_U16(data[28]) = cpu_to_le16(eltorito_checksum); /* Now fill the default boot entry. */ *p++ = 0x88; /* bootable flag */ @@ -1552,11 +1552,11 @@ next_entry: uint32_t boot_size = entry->stats.st_size; if (boot_size % 512) /* round up */ boot_size += 512 - (boot_size % 512); - *((uint16_t *) &data[0]) = cpu_to_le16(boot_size / 512); + AS_U16(data[0]) = cpu_to_le16(boot_size / 512); } else { /* emulation */ - *((uint16_t *) &data[0]) = cpu_to_le16(1); + AS_U16(data[0]) = cpu_to_le16(1); } - *((uint32_t *) &data[2]) = cpu_to_le32(viso->all_sectors * base_factor); + AS_U32(data[2]) = cpu_to_le32(viso->all_sectors * base_factor); viso_pwrite(data, eltorito_offset, 6, 1, viso->tf.fp); } else { p = data; diff --git a/src/chipset/82c100.c b/src/chipset/82c100.c index a9d61b3b9..d3010674a 100644 --- a/src/chipset/82c100.c +++ b/src/chipset/82c100.c @@ -8,8 +8,6 @@ * * Implementation of Chips&Technology's 82C100 chipset. * - * - * * Authors: Miran Grca, * * Copyright 2021 Miran Grca. diff --git a/src/chipset/acc2168.c b/src/chipset/acc2168.c index dbbdc99f6..6378355e6 100644 --- a/src/chipset/acc2168.c +++ b/src/chipset/acc2168.c @@ -8,8 +8,6 @@ * * Implementation of the ACC 2046/2168 chipset * - * - * * Authors: Sarah Walker, * Tiseno100 * diff --git a/src/chipset/ali1409.c b/src/chipset/ali1409.c index 619843cda..b135473d8 100644 --- a/src/chipset/ali1409.c +++ b/src/chipset/ali1409.c @@ -11,8 +11,6 @@ * Note: This chipset has no datasheet, everything were done via * reverse engineering. * - * - * * Authors: Jose Phillips, * Sarah Walker, * diff --git a/src/chipset/ali1429.c b/src/chipset/ali1429.c index e2478078f..d6a4b28a0 100644 --- a/src/chipset/ali1429.c +++ b/src/chipset/ali1429.c @@ -11,8 +11,6 @@ * Note: This chipset has no datasheet, everything were done via * reverse engineering the BIOS of various machines using it. * - * - * * Authors: Tiseno100, * Miran Grca, * diff --git a/src/chipset/ali1435.c b/src/chipset/ali1435.c index ff096ac55..aebd10f32 100644 --- a/src/chipset/ali1435.c +++ b/src/chipset/ali1435.c @@ -7,8 +7,6 @@ * Emulation of ALi M1435 chipset that acts as both the * southbridge. * - * - * * Authors: Miran Grca, * * Copyright 2020 Miran Grca. diff --git a/src/chipset/ali1489.c b/src/chipset/ali1489.c index 80362e244..96ebd4a3d 100644 --- a/src/chipset/ali1489.c +++ b/src/chipset/ali1489.c @@ -8,8 +8,6 @@ * * Implementation of the ALi M1489 chipset. * - * - * * Authors: Tiseno100, * Miran Grca, * diff --git a/src/chipset/ali1531.c b/src/chipset/ali1531.c index 53324f8e6..1603dbca4 100644 --- a/src/chipset/ali1531.c +++ b/src/chipset/ali1531.c @@ -8,8 +8,6 @@ * * Implementation of the ALi M1531B CPU-to-PCI Bridge. * - * - * * Authors: Tiseno100, * * Copyright 2021 Tiseno100. diff --git a/src/chipset/ali1541.c b/src/chipset/ali1541.c index ebbcd7e63..1506d880a 100644 --- a/src/chipset/ali1541.c +++ b/src/chipset/ali1541.c @@ -8,8 +8,6 @@ * * Implementation of the ALi M1541/2 CPU-to-PCI Bridge. * - * - * * Authors: Miran Grca, * * Copyright 2021 Miran Grca. diff --git a/src/chipset/ali1543.c b/src/chipset/ali1543.c index 2f9273736..8ef8e6a20 100644 --- a/src/chipset/ali1543.c +++ b/src/chipset/ali1543.c @@ -8,8 +8,6 @@ * * Implementation of the ALi M1543 Desktop South Bridge. * - * - * * Authors: Tiseno100, * * Copyright 2021 Tiseno100. diff --git a/src/chipset/ali1621.c b/src/chipset/ali1621.c index d44c0f5a9..95602496c 100644 --- a/src/chipset/ali1621.c +++ b/src/chipset/ali1621.c @@ -8,8 +8,6 @@ * * Implementation of the ALi M1621/2 CPU-to-PCI Bridge. * - * - * * Authors: Miran Grca, * * Copyright 2021 Miran Grca. diff --git a/src/chipset/ali6117.c b/src/chipset/ali6117.c index 88bb4b572..a9eb96f88 100644 --- a/src/chipset/ali6117.c +++ b/src/chipset/ali6117.c @@ -8,8 +8,6 @@ * * Implementation of the ALi M6117 SoC. * - * - * * Authors: RichardG, * * Copyright 2020 RichardG. diff --git a/src/chipset/contaq_82c59x.c b/src/chipset/contaq_82c59x.c index 1981fd11c..a9831804f 100644 --- a/src/chipset/contaq_82c59x.c +++ b/src/chipset/contaq_82c59x.c @@ -8,8 +8,6 @@ * * Implementation of the Contaq/Cypress 82C596(A) and 597 chipsets. * - * - * * Authors: Miran Grca, * * Copyright 2021 Miran Grca. diff --git a/src/chipset/cs4031.c b/src/chipset/cs4031.c index cfec9ad30..ad01cd54d 100644 --- a/src/chipset/cs4031.c +++ b/src/chipset/cs4031.c @@ -8,8 +8,6 @@ * * Implementation of the Chips & Technologies CS4031 chipset. * - * - * * Authors: Tiseno100 * * Copyright 2021 Tiseno100 diff --git a/src/chipset/cs8220.c b/src/chipset/cs8220.c index 4c08ecef5..3c3c23767 100644 --- a/src/chipset/cs8220.c +++ b/src/chipset/cs8220.c @@ -160,7 +160,7 @@ cs8220_init(UNUSED(const device_t *info)) /* Dell System 200: 640 kB soldered on-board, any other RAM is expansion. */ - if (!strcmp(machine_get_internal_name(), "dells200")) switch (mem_size) { + if ((machines[machine].init == machine_at_dells200_init)) switch (mem_size) { default: dev->ram_banks[2].virt = 0x00100000; dev->ram_banks[2].phys = 0x000a0000; diff --git a/src/chipset/cs8230.c b/src/chipset/cs8230.c index 0374a44a6..7cdd808c6 100644 --- a/src/chipset/cs8230.c +++ b/src/chipset/cs8230.c @@ -8,8 +8,6 @@ * * Emulation of C&T CS8230 ("386/AT") chipset. * - * - * * Authors: Sarah Walker, * * Copyright 2020 Sarah Walker. diff --git a/src/chipset/et6000.c b/src/chipset/et6000.c index 14ebf852e..d561d90a3 100644 --- a/src/chipset/et6000.c +++ b/src/chipset/et6000.c @@ -8,8 +8,6 @@ * * Implementation of the ETEQ Cheetah ET6000 chipset. * - * - * * Authors: Tiseno100 * * Copyright 2021 Tiseno100 diff --git a/src/chipset/gc100.c b/src/chipset/gc100.c index e9eb05ecf..89dc6c9c0 100644 --- a/src/chipset/gc100.c +++ b/src/chipset/gc100.c @@ -12,8 +12,6 @@ * GC100 chipset, the GC100A chipset has been reverese-engineered. * Thus, its behavior may not be fully accurate. * - * - * * Authors: EngiNerd, * * Copyright 2020-2021 EngiNerd. diff --git a/src/chipset/grid1520.c b/src/chipset/grid1520.c index ce8b1e2a9..e008a0e29 100644 --- a/src/chipset/grid1520.c +++ b/src/chipset/grid1520.c @@ -9,6 +9,7 @@ * Implementation of the GRiD GRiDcase 1520 * * The GRiDcase 1520 is a 286-based portable. + * * These are HDDs supported by GRiD1520 (and probably other 15XX) BIOS * "CP3022",5 * "CP3024",5, 615,4,17 BIOS table type 2 diff --git a/src/chipset/headland.c b/src/chipset/headland.c index 1172d105d..480766103 100644 --- a/src/chipset/headland.c +++ b/src/chipset/headland.c @@ -8,8 +8,6 @@ * * Implementation of the HEADLAND AT286 chipset. * - * - * * Authors: Sarah Walker, * Fred N. van Kempen, * Original by GreatPsycho for PCem. diff --git a/src/chipset/ims8848.c b/src/chipset/ims8848.c index 094ee31f8..13fed304b 100644 --- a/src/chipset/ims8848.c +++ b/src/chipset/ims8848.c @@ -8,8 +8,6 @@ * * Implementation of the IMS 8848/8849 chipset. * - * - * * Authors: Miran Grca, * Tiseno100, * diff --git a/src/chipset/intel_420ex.c b/src/chipset/intel_420ex.c index 662fd0509..daa55c72c 100644 --- a/src/chipset/intel_420ex.c +++ b/src/chipset/intel_420ex.c @@ -9,8 +9,6 @@ * Emulation of Intel 82420EX chipset that acts as both the * northbridge and the southbridge. * - * - * * Authors: Miran Grca, * * Copyright 2020 Miran Grca. diff --git a/src/chipset/intel_4x0.c b/src/chipset/intel_4x0.c index 8e6ce97c3..18f4ee66a 100644 --- a/src/chipset/intel_4x0.c +++ b/src/chipset/intel_4x0.c @@ -8,8 +8,6 @@ * * Implementation of the Intel PCISet chips from 420TX to 440GX. * - * - * * Authors: Miran Grca, * * Copyright 2019-2020 Miran Grca. @@ -1549,7 +1547,7 @@ i4x0_read(int func, int addr, void *priv) with the addition of bits 3 and 0. */ if ((func == 0) && (addr == 0x93) && ((dev->type == INTEL_440FX) || (dev->type == INTEL_440LX) || (dev->type == INTEL_440EX))) ret = (ret & 0xf9) | (pci_read(0x0cf9, NULL) & 0x06); - else if ((func == 0) && (addr == 0x52) && (dev->type == INTEL_430TX) && !strcmp(machine_get_internal_name(), "tomahawk")) + else if ((func == 0) && (addr == 0x52) && (dev->type == INTEL_430TX) && (machines[machine].init == machine_at_tomahawk_init)) ret = 0xb2; } diff --git a/src/chipset/intel_82335.c b/src/chipset/intel_82335.c index bd53e0d05..1dc09a24b 100644 --- a/src/chipset/intel_82335.c +++ b/src/chipset/intel_82335.c @@ -8,8 +8,6 @@ * * Implementation of the Intel 82335(KU82335) chipset. * - * - * * Authors: Tiseno100 * * Copyright 2021 Tiseno100. diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index 5d0c18441..f48950cdc 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -11,8 +11,6 @@ * word 0 - base address * word 1 - bits 1-15 = byte count, bit 31 = end of transfer * - * - * * Authors: Miran Grca, * * Copyright 2016-2020 Miran Grca. @@ -1595,7 +1593,7 @@ piix_init(const device_t *info) - Bit 4: CMOS clear jumper, must be clear; - Bit 0: Password switch, must be clear. */ - if (!strcmp(machine_get_internal_name(), "richmond")) + if (machines[machine].init == machine_at_richmond_init) acpi_set_gpireg2_default(dev->acpi, 0xee); else acpi_set_gpireg2_default(dev->acpi, (dev->type > 4) ? 0xf1 : 0xdd); diff --git a/src/chipset/intel_sio.c b/src/chipset/intel_sio.c index b11ec0765..739785acb 100644 --- a/src/chipset/intel_sio.c +++ b/src/chipset/intel_sio.c @@ -6,8 +6,6 @@ * * Emulation of Intel System I/O PCI chip. * - * - * * Authors: Miran Grca, * * Copyright 2016-2018 Miran Grca. @@ -368,7 +366,7 @@ sio_config_read(uint16_t port, UNUSED(void *priv)) - 1, 0 = M; - 1, 1 = M. */ - if (!strcmp(machine_get_internal_name(), "opti560l")) + if (machines[machine].init == machine_at_opti560l_init) ret = 0x20; else ret = 0xd3; diff --git a/src/chipset/neat.c b/src/chipset/neat.c index 0aa6fe5b6..2d901d035 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -13,8 +13,6 @@ * 8MB of DRAM chips', because it works fine with bus-based * memory expansion. * - * - * * Authors: Fred N. van Kempen, * * Copyright 2018 Fred N. van Kempen. diff --git a/src/chipset/olivetti_eva.c b/src/chipset/olivetti_eva.c index 0dcbdd21f..47614a132 100644 --- a/src/chipset/olivetti_eva.c +++ b/src/chipset/olivetti_eva.c @@ -11,8 +11,6 @@ * Note: This chipset has no datasheet, everything were done via * reverse engineering the BIOS of various machines using it. * - * - * * Authors: EngiNerd * * Copyright 2020-2021 EngiNerd diff --git a/src/chipset/opti283.c b/src/chipset/opti283.c index 81780cf10..12d58fbf3 100644 --- a/src/chipset/opti283.c +++ b/src/chipset/opti283.c @@ -8,8 +8,6 @@ * * Implementation of the OPTi 82C283 chipset. * - * - * * Authors: Tiseno100, * Miran Grca, * diff --git a/src/chipset/opti291.c b/src/chipset/opti291.c index 91b9010e2..62bc0de54 100644 --- a/src/chipset/opti291.c +++ b/src/chipset/opti291.c @@ -8,8 +8,6 @@ * * Implementation of the OPTi 82C291 chipset. * - * - * * Authors: plant/nerd73, Tiseno100 * * Copyright 2020 plant/nerd73. diff --git a/src/chipset/opti391.c b/src/chipset/opti391.c index 7d3c10c98..8f3d9deea 100644 --- a/src/chipset/opti391.c +++ b/src/chipset/opti391.c @@ -8,8 +8,6 @@ * * Implementation of the OPTi 82C391/392 chipset. * - * - * * Authors: Miran Grca, * * Copyright 2021 Miran Grca. diff --git a/src/chipset/opti499.c b/src/chipset/opti499.c index 383b8e3e2..ed7c269b0 100644 --- a/src/chipset/opti499.c +++ b/src/chipset/opti499.c @@ -8,8 +8,6 @@ * * Implementation of the OPTi 82C493/82C499 chipset. * - * - * * Authors: Tiseno100, * Miran Grca, * diff --git a/src/chipset/opti822.c b/src/chipset/opti822.c index 471fbe393..2f416a1c2 100644 --- a/src/chipset/opti822.c +++ b/src/chipset/opti822.c @@ -9,8 +9,6 @@ * Implementation of the OPTi 82C822 VESA Local Bus to PCI * Bridge Interface. * - * - * * Authors: Miran Grca, * * Copyright 2022 Miran Grca. diff --git a/src/chipset/opti895.c b/src/chipset/opti895.c index 16b324963..6edd7c855 100644 --- a/src/chipset/opti895.c +++ b/src/chipset/opti895.c @@ -8,8 +8,6 @@ * * Implementation of the OPTi 82C802G/82C895 chipset. * - * - * * Authors: Tiseno100, * Miran Grca, * diff --git a/src/chipset/scamp.c b/src/chipset/scamp.c index 7ad7b3db2..9019809b5 100644 --- a/src/chipset/scamp.c +++ b/src/chipset/scamp.c @@ -13,8 +13,6 @@ * 8MB of DRAM chips', because it works fine with bus-based * memory expansion. * - * - * * Authors: Sarah Walker, * * Copyright 2020 Sarah Walker. diff --git a/src/chipset/scat.c b/src/chipset/scat.c index 43f93649e..84f7d459d 100644 --- a/src/chipset/scat.c +++ b/src/chipset/scat.c @@ -10,8 +10,6 @@ * * Re-worked version based on the 82C235 datasheet and errata. * - * - * * Authors: Original by GreatPsycho for PCem. * Fred N. van Kempen, * diff --git a/src/chipset/sis_5571_old.c b/src/chipset/sis_5571_old.c index 495137aed..de620c9c1 100644 --- a/src/chipset/sis_5571_old.c +++ b/src/chipset/sis_5571_old.c @@ -8,8 +8,6 @@ * * Implementation of the SiS 5571 Chipset. * - * - * * Authors: Tiseno100, * * Copyright 2021 Tiseno100. diff --git a/src/chipset/sis_85c496.c b/src/chipset/sis_85c496.c index 10bccc1c8..f2c1941d4 100644 --- a/src/chipset/sis_85c496.c +++ b/src/chipset/sis_85c496.c @@ -8,8 +8,6 @@ * * Implementation of the SiS 85c496/85c497 chip. * - * - * * Authors: Miran Grca, * * Copyright 2019-2020 Miran Grca. diff --git a/src/chipset/sis_85c4xx.c b/src/chipset/sis_85c4xx.c index 49d0418ce..aa50ed389 100644 --- a/src/chipset/sis_85c4xx.c +++ b/src/chipset/sis_85c4xx.c @@ -9,8 +9,6 @@ * Emulation of the SiS 85c401/85c402, 85c460, 85c461, and * 85c407/85c471 chipsets. * - * - * * Authors: Miran Grca, * * Copyright 2019-2020 Miran Grca. @@ -766,7 +764,7 @@ sis_85c4xx_reset(void *priv) if (dev->is_471) { dev->regs[0x09] = 0x40; - if (!strcmp(machine_get_internal_name(), "vli486sv2g")) { + if (machines[machine].init == machine_at_vli486sv2g_init) { if (mem_size_mb == 64) dev->regs[0x09] |= 0x1f; else @@ -784,7 +782,7 @@ sis_85c4xx_reset(void *priv) dev->regs[0x09] |= 0x34; else dev->regs[0x09] |= 0x35; - } else if (!strcmp(machine_get_internal_name(), "tg486g")) + } else if (machines[machine].init == machine_at_tg486g_init) dev->regs[0x09] |= ram_tg486g[mem_size_mb]; else dev->regs[0x09] |= ram_471[mem_size_mb]; diff --git a/src/chipset/stpc.c b/src/chipset/stpc.c index f3075323a..56eca8268 100644 --- a/src/chipset/stpc.c +++ b/src/chipset/stpc.c @@ -8,8 +8,6 @@ * * Implementation of the STMicroelectronics STPC series of SoCs. * - * - * * Authors: RichardG, * * Copyright 2020 RichardG. diff --git a/src/chipset/umc_8886.c b/src/chipset/umc_8886.c index 29e2d46da..3725394c3 100644 --- a/src/chipset/umc_8886.c +++ b/src/chipset/umc_8886.c @@ -11,8 +11,6 @@ * Note: This chipset has no datasheet, everything were done via * reverse engineering the BIOS of various machines using it. * - * - * * Authors: Tiseno100, * Miran Grca, * diff --git a/src/chipset/via_apollo.c b/src/chipset/via_apollo.c index 110b1f8e1..974f4e274 100644 --- a/src/chipset/via_apollo.c +++ b/src/chipset/via_apollo.c @@ -8,8 +8,6 @@ * * Implementation of the VIA Apollo series of chips. * - * - * * Authors: Miran Grca, * RichardG, * Tiseno100, diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index 7915b199e..a4d83220b 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -8,8 +8,6 @@ * * Emulation of the VIA PIPC southbridges. * - * - * * Authors: Miran Grca, * RichardG, * diff --git a/src/chipset/via_vt82c49x.c b/src/chipset/via_vt82c49x.c index 3a7bbfdda..35d9c18cc 100644 --- a/src/chipset/via_vt82c49x.c +++ b/src/chipset/via_vt82c49x.c @@ -8,8 +8,6 @@ * * Implementation of the VIA VT82C49X chipset. * - * - * * Authors: Tiseno100, * Miran Grca, * diff --git a/src/chipset/via_vt82c505.c b/src/chipset/via_vt82c505.c index dbbb447c7..3daeec85b 100644 --- a/src/chipset/via_vt82c505.c +++ b/src/chipset/via_vt82c505.c @@ -8,8 +8,6 @@ * * Implementation of the VIA VT82C505 VL/PCI Bridge Controller. * - * - * * Authors: Tiseno100, * Miran Grca, * diff --git a/src/chipset/vl82c480.c b/src/chipset/vl82c480.c index acb3568af..8015137e0 100644 --- a/src/chipset/vl82c480.c +++ b/src/chipset/vl82c480.c @@ -8,8 +8,6 @@ * * Implementation of the VLSI VL82c480 chipset. * - * - * * Authors: Miran Grca, * * Copyright 2020 Miran Grca. @@ -30,6 +28,8 @@ #include <86box/port_92.h> #include <86box/chipset.h> +#define machine_at_prolineamt_init NULL /* checks for a removed machine */ + typedef struct vl82c480_t { uint8_t idx; uint8_t regs[256]; @@ -132,8 +132,8 @@ vl82c480_write(uint16_t addr, uint8_t val, void *priv) break; case 0x02: case 0x03: dev->regs[dev->idx] = val; - if (!strcmp(machine_get_internal_name(), "martin") || - !strcmp(machine_get_internal_name(), "prolineamt")) + if ((machines[machine].init == machine_at_martin_init) || + (machines[machine].init == machine_at_prolineamt_init)) vl82c480_recalc_banks(dev); break; case 0x04: @@ -220,9 +220,9 @@ vl82c480_init(const device_t *info) vl82c480_t *dev = (vl82c480_t *) calloc(1, sizeof(vl82c480_t)); uint32_t sizes[8] = { 0, 0, 1024, 2048, 4096, 8192, 16384, 32768 }; uint32_t ms = mem_size; - uint8_t min_i = !strcmp(machine_get_internal_name(), "prolineamt") ? 1 : 0; - uint8_t min_j = !strcmp(machine_get_internal_name(), "prolineamt") ? 4 : 2; - uint8_t max_j = !strcmp(machine_get_internal_name(), "prolineamt") ? 8 : 7; + uint8_t min_i = (machines[machine].init == machine_at_prolineamt_init) ? 1 : 0; + uint8_t min_j = (machines[machine].init == machine_at_prolineamt_init) ? 4 : 2; + uint8_t max_j = (machines[machine].init == machine_at_prolineamt_init) ? 8 : 7; dev->regs[0x00] = info->local; dev->regs[0x01] = 0xff; @@ -233,7 +233,7 @@ vl82c480_init(const device_t *info) dev->regs[0x07] = 0x21; dev->regs[0x08] = 0x38; - if (!strcmp(machine_get_internal_name(), "prolineamt")) { + if (machines[machine].init == machine_at_prolineamt_init) { dev->banks[0] = 4096; /* Bank 0 is ignored if 64 MB is installed. */ diff --git a/src/chipset/wd76c10.c b/src/chipset/wd76c10.c index ddde7626e..b70785b37 100644 --- a/src/chipset/wd76c10.c +++ b/src/chipset/wd76c10.c @@ -11,7 +11,6 @@ * Authors: Miran Grca, * * Copyright 2024 Miran Grca. - * */ #include #include diff --git a/src/config.c b/src/config.c index 705f4ffc9..d4afe9d81 100644 --- a/src/config.c +++ b/src/config.c @@ -573,7 +573,7 @@ load_input_devices(void) p = ini_section_get_string(cat, "keyboard_type", NULL); if (p != NULL) keyboard_type = keyboard_get_from_internal_name(p); - else if (strstr(machine_get_internal_name(), "pc5086")) + else if (machines[machine].init == machine_xt_pc5086_init) keyboard_type = KEYBOARD_TYPE_PC_XT; else if (machine_has_bus(machine, MACHINE_BUS_PS2_PORTS)) { if (machine_has_flags(machine, MACHINE_KEYBOARD_JIS)) diff --git a/src/cpu/386_common.h b/src/cpu/386_common.h index 8e1f7533f..1efda9d4f 100644 --- a/src/cpu/386_common.h +++ b/src/cpu/386_common.h @@ -542,7 +542,7 @@ fastreadl_fetch(uint32_t a) # if (defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64) return *((uint32_t *) (((uintptr_t) &pccache2[a] & 0x00000000ffffffffULL) | ((uintptr_t) &pccache2[0] & 0xffffffff00000000ULL))); # else - return *((uint32_t *) &pccache2[a]); + return AS_U32(pccache2[a]); # endif } val = fastreadw_fetch(a); diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index ff806297e..bdd93ec5b 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -386,11 +386,7 @@ cpu_is_eligible(const cpu_family_t *cpu_family, int cpu, int machine) return 1; /* Cyrix 6x86MX on the NuPRO 592. */ - if (((cpu_s->cyrix_id & 0xff00) == 0x0400) && (strstr(machine_s->internal_name, "nupro") != NULL)) - return 0; - - /* Cyrix 6x86MX or MII on the P5MMS98. */ - if ((cpu_s->cpu_type == CPU_Cx6x86MX) && (strstr(machine_s->internal_name, "p5mms98") != NULL)) + if (((cpu_s->cyrix_id & 0xff00) == 0x0400) && (machine_s->init == machine_at_nupro592_init)) return 0; /* Check CPU blocklist. */ diff --git a/src/ddma.c b/src/ddma.c index 0ca1bb879..51f2b589e 100644 --- a/src/ddma.c +++ b/src/ddma.c @@ -8,8 +8,6 @@ * * Distributed DMA emulation. * - * - * * Authors: Miran Grca, * * Copyright 2020 Miran Grca. diff --git a/src/device.c b/src/device.c index 07e193ead..cd5adfee0 100644 --- a/src/device.c +++ b/src/device.c @@ -9,8 +9,6 @@ * Implementation of the generic device interface to handle * all devices attached to the emulator. * - * - * * Authors: Fred N. van Kempen, * Miran Grca, * Sarah Walker, diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt index 12835e909..dcad64149 100644 --- a/src/device/CMakeLists.txt +++ b/src/device/CMakeLists.txt @@ -81,6 +81,17 @@ if(ISAMEM_BRAT) target_compile_definitions(dev PRIVATE USE_ISAMEM_BRAT) endif() +if(CMAKE_SYSTEM_NAME MATCHES "Linux") + if(VFIO) + include(CheckIncludeFile) + check_include_file("linux/vfio.h" VFIO_AVAILABLE) + if(VFIO_AVAILABLE) + add_compile_definitions(USE_VFIO) + target_sources(dev PRIVATE vfio.c) + endif() + endif() +endif() + if(LASERXT) target_compile_definitions(dev PRIVATE USE_LASERXT) endif() diff --git a/src/device/bugger.c b/src/device/bugger.c index 6a30df7be..8495cdbe5 100644 --- a/src/device/bugger.c +++ b/src/device/bugger.c @@ -44,9 +44,8 @@ * configuration register (CTRL_SPCFG bit set) but have to * remember that stuff first... * - * - * * Authors: Fred N. van Kempen, + * * Copyright 1989-2018 Fred N. van Kempen. */ #include diff --git a/src/device/cartridge.c b/src/device/cartridge.c index cb3c5e412..639095f72 100644 --- a/src/device/cartridge.c +++ b/src/device/cartridge.c @@ -8,8 +8,6 @@ * * Implementation of the PCjr cartridge emulation. * - * - * * Authors: Miran Grca, * * Copyright 2021 Miran Grca. diff --git a/src/device/clock_ics9xxx.c b/src/device/clock_ics9xxx.c index 02f033e9b..4c08d6b77 100644 --- a/src/device/clock_ics9xxx.c +++ b/src/device/clock_ics9xxx.c @@ -8,8 +8,6 @@ * * Emulation of the ICS9xxx series of clock generators. * - * - * * Authors: RichardG, * * Copyright 2020 RichardG. diff --git a/src/device/hasp.c b/src/device/hasp.c index 07e9ac636..ea8b9b413 100644 --- a/src/device/hasp.c +++ b/src/device/hasp.c @@ -12,8 +12,6 @@ * emulation is enough to satisfy that game, but not Aladdin's * DiagnostiX utility. * - * - * * Authors: RichardG, * Peter Ferrie * diff --git a/src/device/hwm.c b/src/device/hwm.c index 85c689740..13abcb413 100644 --- a/src/device/hwm.c +++ b/src/device/hwm.c @@ -8,13 +8,10 @@ * * Common functions for hardware monitoring chips. * - * - * * Authors: RichardG, * * Copyright 2020 RichardG. */ - #include #include #include diff --git a/src/device/hwm_gl518sm.c b/src/device/hwm_gl518sm.c index cfc16664a..a39511c9a 100644 --- a/src/device/hwm_gl518sm.c +++ b/src/device/hwm_gl518sm.c @@ -8,8 +8,6 @@ * * Emulation of the Genesys Logic GL518SM hardware monitoring chip. * - * - * * Authors: RichardG, * * Copyright 2020 RichardG. diff --git a/src/device/hwm_lm75.c b/src/device/hwm_lm75.c index 29fe2024f..79f9ee6f0 100644 --- a/src/device/hwm_lm75.c +++ b/src/device/hwm_lm75.c @@ -8,8 +8,6 @@ * * Emulation of the National Semiconductor LM75 temperature sensor chip. * - * - * * Authors: RichardG, * * Copyright 2020 RichardG. diff --git a/src/device/hwm_lm78.c b/src/device/hwm_lm78.c index 909713833..27741fd6d 100644 --- a/src/device/hwm_lm78.c +++ b/src/device/hwm_lm78.c @@ -8,8 +8,6 @@ * * Emulation of the National Semiconductor LM78 hardware monitoring chip. * - * - * * Authors: RichardG, * * Copyright 2020 RichardG. diff --git a/src/device/hwm_vt82c686.c b/src/device/hwm_vt82c686.c index 8623a9f6b..f20f8264c 100644 --- a/src/device/hwm_vt82c686.c +++ b/src/device/hwm_vt82c686.c @@ -8,8 +8,6 @@ * * Emulation of the VIA VT82C686A/B integrated hardware monitor. * - * - * * Authors: RichardG, * * Copyright 2020 RichardG. diff --git a/src/device/i2c.c b/src/device/i2c.c index eb80f413b..ca5e549b7 100644 --- a/src/device/i2c.c +++ b/src/device/i2c.c @@ -8,8 +8,6 @@ * * Implementation of the I2C bus and its operations. * - * - * * Authors: RichardG, * * Copyright 2020 RichardG. diff --git a/src/device/i2c_gpio.c b/src/device/i2c_gpio.c index 61a3dbe05..c941a2cc1 100644 --- a/src/device/i2c_gpio.c +++ b/src/device/i2c_gpio.c @@ -8,8 +8,6 @@ * * Emulation of a GPIO-based I2C host controller. * - * - * * Authors: RichardG, * * Copyright 2020 RichardG. diff --git a/src/device/ibm_5161.c b/src/device/ibm_5161.c index 456227676..38f911120 100644 --- a/src/device/ibm_5161.c +++ b/src/device/ibm_5161.c @@ -6,8 +6,6 @@ * * Emulation of the IBM Expansion Unit (5161). * - * - * * Authors: Miran Grca, * * Copyright 2016-2018 Miran Grca. diff --git a/src/device/isapnp.c b/src/device/isapnp.c index ce8f7817f..64f6a1d5f 100644 --- a/src/device/isapnp.c +++ b/src/device/isapnp.c @@ -8,8 +8,6 @@ * * Implementation of ISA Plug and Play. * - * - * * Authors: Miran Grca, * RichardG, * @@ -815,22 +813,22 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) isapnp_log("ISAPnP: >>%s Memory range %d with %d bytes at %06X-%06X to %06X-%06X, align %d", /* %s */ in_df ? ">" : "", /* %d */ mem_range, - /* %d */ *((uint16_t *) &card->rom[i + 8]), - /* %06X */ *((uint16_t *) &card->rom[i + 4]) << 8, + /* %d */ AS_U16(card->rom[i + 8]), + /* %06X */ AS_U16(card->rom[i + 4]) << 8, /* %06X */ ((card->rom[i + 3] & 0x4) ? /* High address. */ - (*((uint16_t *) &card->rom[i + 10]) << 8) : + (AS_U16(card->rom[i + 10]) << 8) : /* Range. */ - (*((uint16_t *) &card->rom[i + 4]) << 8)) + - (*((uint16_t *) &card->rom[i + 10]) << 8), - /* %06X */ *((uint16_t *) &card->rom[i + 6]) << 8, + (AS_U16(card->rom[i + 4]) << 8)) + + (AS_U16(card->rom[i + 10]) << 8), + /* %06X */ AS_U16(card->rom[i + 6]) << 8, /* %06X */ ((card->rom[i + 3] & 0x4) ? /* High address. */ - (*((uint16_t *) &card->rom[i + 10]) << 8) : + (AS_U16(card->rom[i + 10]) << 8) : /* Range. */ - (*((uint16_t *) &card->rom[i + 6]) << 8)) + - (*((uint16_t *) &card->rom[i + 10]) << 8), - /* %d */ *((uint16_t *) &card->rom[i + 8])); + (AS_U16(card->rom[i + 6]) << 8)) + + (AS_U16(card->rom[i + 10]) << 8), + /* %d */ AS_U16(card->rom[i + 8])); res = 1 << mem_range; mem_range++; } else { @@ -847,22 +845,22 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) isapnp_log("ISAPnP: >>%s 32-bit memory range %d with %d bytes at %08X-%08X, align %d", /* %s */ in_df ? ">" : "", /* %d */ mem_range_32, - /* %d */ *((uint32_t *) &card->rom[i + 12]), - /* %08X */ *((uint32_t *) &card->rom[i + 4]), + /* %d */ AS_U32(card->rom[i + 12]), + /* %08X */ AS_U32(card->rom[i + 4]), /* %08X */ ((card->rom[i + 3] & 0x4) ? /* High address. */ - *((uint32_t *) &card->rom[i + 16]) : + AS_U32(card->rom[i + 16]) : /* Range. */ - *((uint32_t *) &card->rom[i + 4])) + - *((uint32_t *) &card->rom[i + 16]), - /* %08X */ *((uint32_t *) &card->rom[i + 8]), + AS_U32(card->rom[i + 4])) + + AS_U32(card->rom[i + 16]), + /* %08X */ AS_U32(card->rom[i + 8]), /* %08X */ ((card->rom[i + 3] & 0x4) ? /* High address. */ - *((uint32_t *) &card->rom[i + 16]) : + AS_U32(card->rom[i + 16]) : /* Range. */ - *((uint32_t *) &card->rom[i + 8])) + - *((uint32_t *) &card->rom[i + 16]), - /* %d */ *((uint32_t *) &card->rom[i + 12])); + AS_U32(card->rom[i + 8])) + + AS_U32(card->rom[i + 16]), + /* %d */ AS_U32(card->rom[i + 12])); res = 1 << (4 + mem_range_32); mem_range_32++; } @@ -972,7 +970,7 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) else /* specific */ res = card->rom[i + 3] & 0x0f; - isapnp_log("ISAPnP: >>%s IRQ index %d with mask %04X, types %01X\n", in_df ? ">" : "", irq, *((uint16_t *) &card->rom[i + 1]), res); + isapnp_log("ISAPnP: >>%s IRQ index %d with mask %04X, types %01X\n", in_df ? ">" : "", irq, AS_U16(card->rom[i + 1]), res); ld->irq_types &= ~(0x0f << (4 * irq)); ld->irq_types |= res << (4 * irq); @@ -1038,7 +1036,7 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) break; } - isapnp_log("ISAPnP: >>%s I/O range %d with %d ports at %04X-%04X, align %d, %d-bit decode\n", in_df ? ">" : "", io, card->rom[i + 7], *((uint16_t *) &card->rom[i + 2]), *((uint16_t *) &card->rom[i + 4]), card->rom[i + 6], (card->rom[i + 1] & 0x01) ? 16 : 10); + isapnp_log("ISAPnP: >>%s I/O range %d with %d ports at %04X-%04X, align %d, %d-bit decode\n", in_df ? ">" : "", io, card->rom[i + 7], AS_U16(card->rom[i + 2]), AS_U16(card->rom[i + 4]), card->rom[i + 6], (card->rom[i + 1] & 0x01) ? 16 : 10); if (card->rom[i + 1] & 0x01) ld->io_16bit |= 1 << io; @@ -1063,7 +1061,7 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) break; } - isapnp_log("ISAPnP: >>%s Fixed I/O range %d with %d ports at %04X\n", in_df ? ">" : "", io, card->rom[i + 3], *((uint16_t *) &card->rom[i + 1])); + isapnp_log("ISAPnP: >>%s Fixed I/O range %d with %d ports at %04X\n", in_df ? ">" : "", io, card->rom[i + 3], AS_U16(card->rom[i + 1])); /* Fixed I/O port ranges of this kind are always 10-bit. */ ld->io_16bit &= ~(1 << io); @@ -1117,6 +1115,8 @@ isapnp_enable_card(void *priv, uint8_t enable) /* Enable or disable the card. */ if (!!enable ^ !!card->enable) card->state = (enable == ISAPNP_CARD_FORCE_CONFIG) ? PNP_STATE_CONFIG : PNP_STATE_WAIT_FOR_KEY; + if (enable == ISAPNP_CARD_FORCE_SLEEP) + card->state = PNP_STATE_SLEEP; int old_enable = card->enable; card->enable = enable; diff --git a/src/device/isartc.c b/src/device/isartc.c index 664793db3..06b7767c8 100644 --- a/src/device/isartc.c +++ b/src/device/isartc.c @@ -26,8 +26,6 @@ * NOTE: The IRQ functionalities have been implemented, but not yet * tested, as I need to write test software for them first :) * - * - * * Authors: Fred N. van Kempen, * * Copyright 2018 Fred N. van Kempen. @@ -523,7 +521,7 @@ isartc_init(const device_t *info) { rtcdev_t *dev; int is_at = IS_AT(machine); - is_at = is_at || !strcmp(machine_get_internal_name(), "xi8088"); + is_at = is_at || (machines[machine].init == machine_xt_xi8088_init); /* Create a device instance. */ dev = (rtcdev_t *) calloc(1, sizeof(rtcdev_t)); diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 186804e22..0f3bd5600 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -806,15 +806,15 @@ write_p2(atkbc_t *dev, uint8_t val) cpu_set_edx(); flushmmucache(); if ((kbc_ven == KBC_VEN_ALI) || - !strcmp(machine_get_internal_name(), "spc7700plw") || - !strcmp(machine_get_internal_name(), "pl4600c")) + (machines[machine].init == machine_at_spc7700plw_init) || + (machines[machine].init == machine_at_pl4600c_init)) smbase = 0x00030000; /* Yes, this is a hack, but until someone gets ahold of the real PCD-2L and can find out what they actually did to make it boot from FFFFF0 correctly despite A20 being gated when the CPU is reset, this will have to do. */ - if ((kbc_ven == KBC_VEN_SIEMENS) || !strcmp(machine_get_internal_name(), "acera1g")) + if ((kbc_ven == KBC_VEN_SIEMENS) || (machines[machine].init == machine_at_acera1g_init)) is486 ? loadcs(0xf000) : loadcs_2386(0xf000); } } @@ -1187,7 +1187,7 @@ write_cmd_ami(void *priv, uint8_t val) kbc_at_log("ATkbc: set KBC lines P22-P23 (P2 bits 2-3) low\n"); if (!(dev->flags & DEVICE_PCI)) write_p2(dev, dev->p2 & ~(4 << (val & 0x01))); - if (strstr(machine_get_internal_name(), "sb486pv") != NULL) + if (machines[machine].init == machine_at_sb486pv_init) kbc_delay_to_ob(dev, 0x03, 0, 0x00); else kbc_delay_to_ob(dev, dev->ob, 0, 0x00); @@ -2627,7 +2627,7 @@ kbc_at_process_cmd(void *priv) if (dev->ib == 0xbb) break; - if (strstr(machine_get_internal_name(), "pb41") != NULL) + if (machines[machine].init == machine_at_pb410a_init) cpu_override_dynarec = 1; if (dev->misc_flags & FLAG_PS2) { @@ -2759,7 +2759,7 @@ kbc_at_port_1_read(uint16_t port, void *priv) */ if (!(dev->misc_flags & FLAG_PS2) && (dev->irq[0] != 0xffff)) picintclevel(1 << dev->irq[0], &dev->irq_state); - if ((strstr(machine_get_internal_name(), "pb41") != NULL) && (cpu_override_dynarec == 1)) + if ((machines[machine].init == machine_at_pb410a_init) && (cpu_override_dynarec == 1)) cpu_override_dynarec = 0; kbc_at_log("ATkbc: [%04X:%08X] read (%04X) = %02X\n", CS, cpu_state.pc, port, ret); diff --git a/src/device/kbc_xt.c b/src/device/kbc_xt.c index 176f1df43..a9fa8bf6c 100644 --- a/src/device/kbc_xt.c +++ b/src/device/kbc_xt.c @@ -8,8 +8,6 @@ * * Implementation of the XT-style keyboard. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, diff --git a/src/device/keyboard.c b/src/device/keyboard.c index 524593eb7..7806418dd 100644 --- a/src/device/keyboard.c +++ b/src/device/keyboard.c @@ -8,8 +8,6 @@ * * General keyboard driver interface. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, diff --git a/src/device/keyboard_xt.c b/src/device/keyboard_xt.c index 2936868b0..d31d5f027 100644 --- a/src/device/keyboard_xt.c +++ b/src/device/keyboard_xt.c @@ -8,8 +8,6 @@ * * Implementation of the XT-style keyboard. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, diff --git a/src/device/mouse.c b/src/device/mouse.c index fb7fd020f..eb7557faf 100644 --- a/src/device/mouse.c +++ b/src/device/mouse.c @@ -11,8 +11,6 @@ * TODO: Add the Genius bus- and serial mouse. * Remove the '3-button' flag from mouse types. * - * - * * Authors: Miran Grca, * Fred N. van Kempen, * diff --git a/src/device/mouse_bus.c b/src/device/mouse_bus.c index dd71ef11e..cd54f981a 100644 --- a/src/device/mouse_bus.c +++ b/src/device/mouse_bus.c @@ -57,8 +57,6 @@ * Microsoft Windows NT 3.1 * Microsoft Windows 98 SE * - * - * * Authors: Miran Grca, * Fred N. van Kempen, * diff --git a/src/device/mouse_microtouch_touchscreen.c b/src/device/mouse_microtouch_touchscreen.c index 512fcc0df..4c4f46708 100644 --- a/src/device/mouse_microtouch_touchscreen.c +++ b/src/device/mouse_microtouch_touchscreen.c @@ -8,8 +8,6 @@ * * 3M MicroTouch Serial emulation. * - * - * * Authors: Cacodemon345, mourix * * Copyright 2024 Cacodemon345 diff --git a/src/device/nec_mate_unk.c b/src/device/nec_mate_unk.c index c0393eaa2..c4a697bd8 100644 --- a/src/device/nec_mate_unk.c +++ b/src/device/nec_mate_unk.c @@ -8,8 +8,6 @@ * * Implementation of the NEC Mate NX MA30D/23D Unknown Readout. * - * - * * Authors: Miran Grca, * * Copyright 2020-2023 Miran Grca. diff --git a/src/device/novell_cardkey.c b/src/device/novell_cardkey.c index edc32b879..0b1045777 100644 --- a/src/device/novell_cardkey.c +++ b/src/device/novell_cardkey.c @@ -9,12 +9,10 @@ * Implementation of the Novell NetWare 2.x Key Card, which * was used for anti-piracy protection. * - * * Authors: Cacodemon345 * * Copyright 2024 Cacodemon345. */ - #include #include #include diff --git a/src/device/pci_bridge.c b/src/device/pci_bridge.c index bf49baf14..d9aeeffb6 100644 --- a/src/device/pci_bridge.c +++ b/src/device/pci_bridge.c @@ -8,13 +8,10 @@ * * Implementation of PCI-PCI and host-AGP bridges. * - * - * * Authors: RichardG, * * Copyright 2020 RichardG. */ - #include #include #include diff --git a/src/device/phoenix_486_jumper.c b/src/device/phoenix_486_jumper.c index a3e2f0e7e..1b6270984 100644 --- a/src/device/phoenix_486_jumper.c +++ b/src/device/phoenix_486_jumper.c @@ -8,8 +8,6 @@ * * Implementation of the Phoenix 486 Jumper Readout. * - * - * * Authors: Miran Grca, * Tiseno100, * diff --git a/src/device/postcard.c b/src/device/postcard.c index ec031c2b8..908adfe72 100644 --- a/src/device/postcard.c +++ b/src/device/postcard.c @@ -8,8 +8,6 @@ * * Implementation of a port 80h POST diagnostic card. * - * - * * Authors: RichardG, * * Copyright 2020 RichardG. diff --git a/src/device/serial.c b/src/device/serial.c index ad9abfe5d..63f20cbee 100644 --- a/src/device/serial.c +++ b/src/device/serial.c @@ -10,8 +10,6 @@ * * Now passes all the AMIDIAG tests. * - * - * * Authors: Miran Grca, * Fred N. van Kempen, * diff --git a/src/device/serial_passthrough.c b/src/device/serial_passthrough.c index 249380b4f..6cf273fd1 100644 --- a/src/device/serial_passthrough.c +++ b/src/device/serial_passthrough.c @@ -8,14 +8,12 @@ * * Implementation of Serial passthrough device. * - * * Authors: Andreas J. Reichel , * Jasmine Iwanek * * Copyright 2021 Andreas J. Reichel. * Copyright 2021-2025 Jasmine Iwanek. */ - #include #include #include diff --git a/src/device/smbus_piix4.c b/src/device/smbus_piix4.c index ae37c72c4..ae263b484 100644 --- a/src/device/smbus_piix4.c +++ b/src/device/smbus_piix4.c @@ -8,8 +8,6 @@ * * Implementation of a generic PIIX4-compatible SMBus host controller. * - * - * * Authors: RichardG, * * Copyright 2020 RichardG. diff --git a/src/device/unittester.c b/src/device/unittester.c index 0e864aa0b..48486efce 100644 --- a/src/device/unittester.c +++ b/src/device/unittester.c @@ -11,8 +11,6 @@ * If modifying the protocol, you MUST modify the specification * and increment the version number. * - * - * * Authors: GreaseMonkey, * * Copyright 2024 GreaseMonkey. diff --git a/src/device/vfio.c b/src/device/vfio.c new file mode 100644 index 000000000..b5fc077b8 --- /dev/null +++ b/src/device/vfio.c @@ -0,0 +1,3377 @@ +/* + * 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. + * + * Virtual Function I/O PCI passthrough handler. + * + * Authors: RichardG, + * + * Copyright 2021-2025 RichardG. + */ +#define _FILE_OFFSET_BITS 64 +#define _LARGEFILE64_SOURCE 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "cpu.h" +#include <86box/86box.h> +#include <86box/ini.h> +#include <86box/config.h> +#include <86box/device.h> +#include <86box/i2c.h> /* log2i */ +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/path.h> +#include <86box/pci.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/timer.h> +#include <86box/video.h> + +/* Just so we don't have to include Linux's pci.h, which + has some defines that conflict with our own pci.h */ +#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) +#define PCI_FUNC(devfn) ((devfn) & 0x07) + +enum { + NVIDIA_3D0_NONE = 0, + NVIDIA_3D0_SELECT, + NVIDIA_3D0_WINDOW, + NVIDIA_3D0_READ, + NVIDIA_3D0_WRITE +}; + +typedef struct { + int fd; + uint64_t precalc_offset; + uint64_t offset; + uint64_t size; + uint32_t emulated_offset; + uint8_t *mmap_base; + uint8_t *mmap_precalc; + uint8_t type; + uint8_t bar_id; + uint8_t read : 1; + uint8_t write : 1; + mem_mapping_t mem_mapping; + char name[20]; + struct _vfio_device_ *dev; + + struct { + mem_mapping_t mem_mappings[2]; + + struct { + uint32_t offset; + } iomirror; + + struct { + uint32_t offset; + } configmirror; + + struct { + struct { + uint32_t start; + uint32_t end; + } offset[2]; + uint32_t index; + } configwindow; + } quirks; +} vfio_region_t; + +typedef struct { + struct _vfio_device_ *dev; + int fd; + int type; + int vector; + uint16_t msix_offset; +} vfio_irq_t; + +typedef struct _vfio_device_ { + int fd; + uint8_t mem_enabled : 1; + uint8_t io_enabled : 1; + uint8_t rom_enabled : 1; + uint8_t can_reset : 1; + uint8_t can_flr_reset : 1; + uint8_t can_pm_reset : 1; + uint8_t can_hot_reset : 1; + uint8_t slot; + uint8_t bar_count; + uint8_t pm_cap; + uint8_t msi_cap; + uint8_t msix_cap; + uint8_t pcie_cap; + uint8_t af_cap; + char *name; + char *rom_fn; + + vfio_region_t bars[6]; + vfio_region_t rom; + vfio_region_t config; + vfio_region_t vga_io_lo; + vfio_region_t vga_io_hi; + vfio_region_t vga_mem; + + struct { + uint8_t type; + int vector_count; + vfio_irq_t *vectors; + + struct { + int raised; + uint8_t pin; + uint8_t state; + } intx; + struct { + uint32_t address; + uint32_t address_upper; + uint32_t pending; + uint32_t mask; + uint16_t ctl; + uint16_t data; + uint16_t vector_enable_mask; + uint8_t vector_count; + uint8_t vector_enable_count; + } msi; + struct { + mem_mapping_t table_mapping; + mem_mapping_t pba_mapping; + uint32_t table_offset; + uint32_t pba_offset; + uint32_t table_offset_precalc; + uint32_t pba_offset_precalc; + uint16_t ctl; + uint16_t vector_count; + uint16_t table_size; + uint16_t pba_size; + uint8_t table_bar; + uint8_t pba_bar; + uint8_t *table; + uint8_t *pba; + } msix; + } irq; + + struct { + union { + struct { + vfio_region_t *bar; + } ati3c3; + + struct { + uint64_t master_enable; + uint8_t bar_enable; + } nvidiabar5; + + struct { + uint32_t index; + uint8_t state; + } nvidia3d0; + }; + } quirks; + + struct _vfio_device_ *next; +} vfio_device_t; + +typedef struct _vfio_group_ { + int id; + int fd; + + vfio_device_t *first_device; + vfio_device_t *current_device; + + struct _vfio_group_ *next; +} vfio_group_t; + +static video_timings_t timing_default = { VIDEO_PCI, 8, 16, 32, 8, 16, 32 }; +static int container_fd = -1; +static int epoll_fd = -1; +static int irq_thread_wake_fd = -1; +static int closing = 0; +static int intx_high = 0; +static int timing_readb = 0; +static int timing_readw = 0; +static int timing_readl = 0; +static int timing_writeb = 0; +static int timing_writew = 0; +static int timing_writel = 0; +static vfio_group_t *first_group = NULL; +static vfio_group_t *current_group; +static thread_t *irq_thread; +static event_t *irq_event; +static event_t *irq_thread_resume; +static pc_timer_t irq_timer; +static vfio_irq_t *current_irq = NULL; +static const device_t vfio_device; + +#define ENABLE_VFIO_LOG 2 +#ifdef ENABLE_VFIO_LOG +int vfio_do_log = ENABLE_VFIO_LOG; + +static void +vfio_log(const char *fmt, ...) +{ + va_list ap; + + if (vfio_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} + +# if ENABLE_VFIO_LOG == 2 +# define vfio_log_op vfio_log +# else +# define vfio_log_op(fmt, ...) +# endif +#else +# define vfio_log(fmt, ...) +# define vfio_log_op(fmt, ...) +#endif + +static uint8_t vfio_bar_gettype(vfio_device_t *dev, vfio_region_t *bar); +static uint8_t vfio_config_readb(int func, int addr, void *priv); +static uint16_t vfio_config_readw(int func, int addr, void *priv); +static uint32_t vfio_config_readl(int func, int addr, void *priv); +static void vfio_config_writeb(int func, int addr, uint8_t val, void *priv); +static void vfio_config_writew(int func, int addr, uint16_t val, void *priv); +static void vfio_config_writel(int func, int addr, uint32_t val, void *priv); +static void vfio_irq_intx_setpin(vfio_device_t *dev); +static void vfio_irq_msi_disable(vfio_device_t *dev); +static void vfio_irq_msix_disable(vfio_device_t *dev); +static void vfio_irq_msix_updatemask(vfio_device_t *dev, uint16_t offset); +static void vfio_irq_enable(vfio_device_t *dev, int type); + +#define VFIO_RW(space, length_char, addr_type, addr_slength, val_type, val_slength) \ + static val_type \ + vfio_##space##_read##length_char##_fd(addr_type addr, void *priv) \ + { \ + register vfio_region_t *region = (vfio_region_t *) priv; \ + val_type ret; \ + if (pread(region->fd, &ret, sizeof(ret), region->precalc_offset + addr) != sizeof(ret)) \ + ret = -1; \ + vfio_log_op("[%04X:%08X] VFIO: " #space "_read" #length_char "_fd(%0" #addr_slength "X) = %0" #val_slength "X\n", CS, cpu_state.pc, addr, ret); \ + cycles -= timing_read##length_char; \ + intx_high = 0; \ + return ret; \ + } \ + \ + static void \ + vfio_##space##_write##length_char##_fd(addr_type addr, val_type val, void *priv) \ + { \ + register vfio_region_t *region = (vfio_region_t *) priv; \ + vfio_log_op("[%04X:%08X] VFIO: " #space "_write" #length_char "_fd(%0" #addr_slength "X, %0" #val_slength "X)\n", CS, cpu_state.pc, addr, val); \ + (void) !pwrite(region->fd, &val, sizeof(val), region->precalc_offset + addr); \ + cycles -= timing_write##length_char; \ + intx_high = 0; \ + } \ + \ + static val_type \ + vfio_##space##_read##length_char##_mm(addr_type addr, void *priv) \ + { \ + register val_type ret = *((val_type *) &((uint8_t *) priv)[addr]); \ + vfio_log_op("[%04X:%08X] VFIO: " #space "_read" #length_char "_mm(%0" #addr_slength "X) = %0" #val_slength "X\n", CS, cpu_state.pc, addr, ret); \ + cycles -= timing_read##length_char; \ + intx_high = 0; \ + return ret; \ + } \ + \ + static void \ + vfio_##space##_write##length_char##_mm(addr_type addr, val_type val, void *priv) \ + { \ + vfio_log_op("[%04X:%08X] VFIO: " #space "_write" #length_char "_mm(%0" #addr_slength "X, %0" #val_slength "X)\n", CS, cpu_state.pc, addr, val); \ + *((val_type *) &((uint8_t *) priv)[addr]) = val; \ + cycles -= timing_write##length_char; \ + intx_high = 0; \ + } + +VFIO_RW(mem, b, uint32_t, 8, uint8_t, 2) +VFIO_RW(mem, w, uint32_t, 8, uint16_t, 4) +VFIO_RW(mem, l, uint32_t, 8, uint32_t, 8) +VFIO_RW(io, b, uint16_t, 4, uint8_t, 2) +VFIO_RW(io, w, uint16_t, 4, uint16_t, 4) +VFIO_RW(io, l, uint16_t, 4, uint32_t, 8) + +static void +vfio_quirk_capture_io(vfio_device_t *dev, vfio_region_t *bar, + uint16_t base, uint16_t size, uint8_t enable, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv)) +{ + /* Remove quirk handler from port range. */ + io_removehandler(base, size, + bar->read ? inb : NULL, + bar->read ? inw : NULL, + bar->read ? inl : NULL, + bar->write ? outb : NULL, + bar->write ? outw : NULL, + bar->write ? outl : NULL, + dev ? ((void *) dev) : ((void *) bar)); + + if (enable) { + /* Remove existing handler from port range. */ + if (bar->mmap_base) /* mmap available */ + io_removehandler(base, size, + bar->read ? vfio_io_readb_mm : NULL, + bar->read ? vfio_io_readw_mm : NULL, + bar->read ? vfio_io_readl_mm : NULL, + bar->write ? vfio_io_writeb_mm : NULL, + bar->write ? vfio_io_writew_mm : NULL, + bar->write ? vfio_io_writel_mm : NULL, + bar->mmap_precalc); + else /* mmap not available */ + io_removehandler(base, size, + bar->read ? vfio_io_readb_fd : NULL, + bar->read ? vfio_io_readw_fd : NULL, + bar->read ? vfio_io_readl_fd : NULL, + bar->write ? vfio_io_writeb_fd : NULL, + bar->write ? vfio_io_writew_fd : NULL, + bar->write ? vfio_io_writel_fd : NULL, + bar); + + /* Add quirk handler to port range. */ + io_sethandler(base, size, + bar->read ? inb : NULL, + bar->read ? inw : NULL, + bar->read ? inl : NULL, + bar->write ? outb : NULL, + bar->write ? outw : NULL, + bar->write ? outl : NULL, + dev ? ((void *) dev) : ((void *) bar)); + } +} + +static uint8_t +vfio_quirk_configmirror_readb(uint32_t addr, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + vfio_device_t *dev = bar->dev; + + /* Cascade to the main handler. */ + vfio_mem_readb_fd(addr, bar); + + /* Read configuration register. */ + uint8_t ret = vfio_config_readb(0, addr - bar->quirks.configmirror.offset, dev); + vfio_log_op("VFIO %s: Config mirror: Read %02X from index %02X\n", + dev->name, ret, addr - bar->quirks.configmirror.offset); + + return ret; +} + +static uint16_t +vfio_quirk_configmirror_readw(uint32_t addr, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + vfio_device_t *dev = bar->dev; + + /* Cascade to the main handler. */ + vfio_mem_readw_fd(addr, bar); + + /* Read configuration register. */ + uint16_t ret = vfio_config_readw(0, addr - bar->quirks.configmirror.offset, dev); + vfio_log_op("VFIO %s: Config mirror: Read %04X from index %02X\n", + dev->name, ret, addr - bar->quirks.configmirror.offset); + + return ret; +} + +static uint32_t +vfio_quirk_configmirror_readl(uint32_t addr, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + vfio_device_t *dev = bar->dev; + + /* Cascade to the main handler. */ + vfio_mem_readl_fd(addr, bar); + + /* Read configuration register. */ + uint32_t ret = vfio_config_readl(0, addr - bar->quirks.configmirror.offset, dev); + vfio_log_op("VFIO %s: Config mirror: Read %08X from index %02X\n", + dev->name, ret, addr - bar->quirks.configmirror.offset); + + return ret; +} + +static void +vfio_quirk_configmirror_writeb(uint32_t addr, uint8_t val, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + vfio_device_t *dev = bar->dev; + + /* Write configuration register. */ + vfio_log_op("VFIO %s: Config mirror: Write %02X to index %02X\n", + dev->name, val, addr - bar->quirks.configmirror.offset); + vfio_config_writeb(0, addr - bar->quirks.configmirror.offset, val, dev); +} + +static void +vfio_quirk_configmirror_writew(uint32_t addr, uint16_t val, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + vfio_device_t *dev = bar->dev; + + /* Write configuration register. */ + vfio_log_op("VFIO %s: Config mirror: Write %04X to index %02X\n", + dev->name, val, addr - bar->quirks.configmirror.offset); + vfio_config_writew(0, addr - bar->quirks.configmirror.offset, val, dev); +} + +static void +vfio_quirk_configmirror_writel(uint32_t addr, uint32_t val, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + vfio_device_t *dev = bar->dev; + + /* Write configuration register. */ + vfio_log_op("VFIO %s: Config mirror: Write %08X to index %02X\n", + dev->name, val, addr - bar->quirks.configmirror.offset); + vfio_config_writel(0, addr - bar->quirks.configmirror.offset, val, dev); +} + +static void +vfio_quirk_configmirror(vfio_device_t *dev, vfio_region_t *bar, + uint32_t offset, uint8_t mapping_slot, uint8_t enable) +{ + /* Get the additional memory mapping structure. */ + mem_mapping_t *mapping = &bar->quirks.mem_mappings[mapping_slot]; + + vfio_log("VFIO %s: %sapping configuration space mirror for %s @ %08X\n", + dev->name, enable ? "M" : "Unm", bar->name, bar->emulated_offset + offset); + + /* Add mapping if it wasn't already added. + Being added after region setup, it should override the main BAR mapping. */ + if (!mapping->base) + mem_mapping_add(mapping, 0, 0, + vfio_quirk_configmirror_readb, + vfio_quirk_configmirror_readw, + vfio_quirk_configmirror_readl, + vfio_quirk_configmirror_writeb, + vfio_quirk_configmirror_writew, + vfio_quirk_configmirror_writel, + NULL, MEM_MAPPING_EXTERNAL, bar); + + /* Store start offset. */ + bar->quirks.configmirror.offset = bar->emulated_offset + offset; + + /* Enable or disable mapping. */ + if (enable) + mem_mapping_set_addr(mapping, bar->emulated_offset + offset, 256); + else + mem_mapping_disable(mapping); +} + +static void +vfio_quirk_configwindow_index_writeb(uint16_t addr, uint8_t val, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + vfio_device_t *dev = bar->dev; + + /* Write configuration register index. */ + vfio_log_op("VFIO %s: Config window: Write index[%d] %02X\n", + dev->name, addr & 3, val); + uint8_t offset = (addr & 3) << 3; + bar->quirks.configwindow.index &= ~(0x000000ff << offset); + bar->quirks.configwindow.index |= val << offset; + + /* Cascade to the main handler. */ + vfio_io_writeb_fd(addr, val, bar); +} + +static void +vfio_quirk_configwindow_index_writew(uint16_t addr, uint16_t val, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + vfio_device_t *dev = bar->dev; + + /* Write configuration register index. */ + vfio_log_op("VFIO %s: Config window: Write index[%d] %04X\n", + dev->name, addr & 2, val); + uint8_t offset = (addr & 2) << 3; + bar->quirks.configwindow.index &= ~(0x0000ffff << offset); + bar->quirks.configwindow.index |= val << offset; + + /* Cascade to the main handler. */ + vfio_io_writew_fd(addr, val, bar); +} + +static void +vfio_quirk_configwindow_index_writel(uint16_t addr, uint32_t val, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + vfio_device_t *dev = bar->dev; + + /* Write configuration register index. */ + vfio_log_op("VFIO %s: Config window: Write index %08X\n", + dev->name, val); + bar->quirks.configwindow.index = val; + + /* Cascade to the main handler. */ + vfio_io_writel_fd(addr, val, bar); +} + +static uint8_t +vfio_quirk_configwindow_data_readb(uint16_t addr, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + vfio_device_t *dev = bar->dev; + + /* Cascade to the main handler. */ + uint8_t ret = vfio_io_readb_fd(addr, bar); + + /* Read configuration register if part of the main PCI configuration space. */ + uint32_t index = bar->quirks.configwindow.index; + if ((index >= bar->quirks.configwindow.offset[0].start) && (index <= bar->quirks.configwindow.offset[0].end)) { + ret = vfio_config_readb(0, index - bar->quirks.configwindow.offset[0].start, dev); + vfio_log_op("VFIO %s: Config window: Read %02X from primary index %08X\n", + dev->name, ret, index); + } else if ((index >= bar->quirks.configwindow.offset[1].start) && (index <= bar->quirks.configwindow.offset[1].end)) { + ret = vfio_config_readb(0, index - bar->quirks.configwindow.offset[1].start, dev); + vfio_log_op("VFIO %s: Config window: Read %02X from secondary index %08X\n", + dev->name, ret, index); + } + + return ret; +} + +static uint16_t +vfio_quirk_configwindow_data_readw(uint16_t addr, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + vfio_device_t *dev = bar->dev; + + /* Cascade to the main handler. */ + uint16_t ret = vfio_io_readw_fd(addr, bar); + + /* Read configuration register if part of the main PCI configuration space. */ + uint32_t index = bar->quirks.configwindow.index; + if ((index >= bar->quirks.configwindow.offset[0].start) && (index <= bar->quirks.configwindow.offset[0].end)) { + ret = vfio_config_readw(0, index - bar->quirks.configwindow.offset[0].start, dev); + vfio_log_op("VFIO %s: Config window: Read %04X from primary index %08X\n", + dev->name, ret, index); + } else if ((index >= bar->quirks.configwindow.offset[1].start) && (index <= bar->quirks.configwindow.offset[1].end)) { + ret = vfio_config_readw(0, index - bar->quirks.configwindow.offset[1].start, dev); + vfio_log_op("VFIO %s: Config window: Read %04X from secondary index %08X\n", + dev->name, ret, index); + } + + return ret; +} + +static uint32_t +vfio_quirk_configwindow_data_readl(uint16_t addr, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + vfio_device_t *dev = bar->dev; + + /* Cascade to the main handler. */ + uint32_t ret = vfio_io_readl_fd(addr, bar); + + /* Read configuration register if part of the main PCI configuration space. */ + uint32_t index = bar->quirks.configwindow.index; + if ((index >= bar->quirks.configwindow.offset[0].start) && (index <= bar->quirks.configwindow.offset[0].end)) { + ret = vfio_config_readl(0, index - bar->quirks.configwindow.offset[0].start, dev); + vfio_log_op("VFIO %s: Config window: Read %08X from primary index %08X\n", + dev->name, ret, index); + } else if ((index >= bar->quirks.configwindow.offset[1].start) && (index <= bar->quirks.configwindow.offset[1].end)) { + ret = vfio_config_readl(0, index - bar->quirks.configwindow.offset[1].start, dev); + vfio_log_op("VFIO %s: Config window: Read %08X from secondary index %08X\n", + dev->name, ret, index); + } + + return ret; +} + +static void +vfio_quirk_configwindow_data_writeb(uint16_t addr, uint8_t val, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + vfio_device_t *dev = bar->dev; + + /* Write configuration register if part of the main PCI configuration space. */ + uint32_t index = bar->quirks.configwindow.index; + if ((index >= bar->quirks.configwindow.offset[0].start) && (index <= bar->quirks.configwindow.offset[0].end)) { + vfio_log_op("VFIO %s: Config window: Write %02X to primary index %08X\n", + dev->name, val, index); + vfio_config_writeb(0, index - bar->quirks.configwindow.offset[0].start, val, dev); + return; + } else if ((index >= bar->quirks.configwindow.offset[1].start) && (index <= bar->quirks.configwindow.offset[1].end)) { + vfio_log_op("VFIO %s: Config window: Write %02X to secondary index %08X\n", + dev->name, val, index); + vfio_config_writeb(0, index - bar->quirks.configwindow.offset[1].start, val, dev); + return; + } + + /* Cascade to the main handler. */ + vfio_io_writeb_fd(addr, val, bar); +} + +static void +vfio_quirk_configwindow_data_writew(uint16_t addr, uint16_t val, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + vfio_device_t *dev = bar->dev; + + /* Write configuration register if part of the main PCI configuration space. */ + uint32_t index = bar->quirks.configwindow.index; + if ((index >= bar->quirks.configwindow.offset[0].start) && (index <= bar->quirks.configwindow.offset[0].end)) { + vfio_log_op("VFIO %s: Config window: Write %04X to primary index %08X\n", + dev->name, val, index); + vfio_config_writew(0, index - bar->quirks.configwindow.offset[0].start, val, dev); + return; + } else if ((index >= bar->quirks.configwindow.offset[1].start) && (index <= bar->quirks.configwindow.offset[1].end)) { + vfio_log_op("VFIO %s: Config window: Write %04X to secondary index %08X\n", + dev->name, val, index); + vfio_config_writew(0, index - bar->quirks.configwindow.offset[1].start, val, dev); + return; + } + + /* Cascade to the main handler. */ + vfio_io_writew_fd(addr, val, bar); +} + +static void +vfio_quirk_configwindow_data_writel(uint16_t addr, uint32_t val, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + vfio_device_t *dev = bar->dev; + + /* Write configuration register if part of the main PCI configuration space. */ + uint32_t index = bar->quirks.configwindow.index; + if ((index >= bar->quirks.configwindow.offset[0].start) && (index <= bar->quirks.configwindow.offset[0].end)) { + vfio_log_op("VFIO %s: Config window: Write %08X to primary index %08X\n", + dev->name, val, index); + vfio_config_writel(0, index - bar->quirks.configwindow.offset[0].start, val, dev); + return; + } else if ((index >= bar->quirks.configwindow.offset[1].start) && (index <= bar->quirks.configwindow.offset[1].end)) { + vfio_log_op("VFIO %s: Config window: Write %08X to secondary index %08X\n", + dev->name, val, index); + vfio_config_writel(0, index - bar->quirks.configwindow.offset[1].start, val, dev); + return; + } + + /* Cascade to the main handler. */ + vfio_io_writel_fd(addr, val, bar); +} + +static void +vfio_quirk_configwindow(vfio_device_t *dev, vfio_region_t *bar, + uint16_t index_offset, uint16_t index_size, + uint16_t data_offset, uint16_t data_size, + uint32_t window_offset0, uint32_t window_offset1, uint8_t enable) +{ + vfio_log("VFIO %s: %sapping configuration space window for %s @ %04X and %04X\n", + dev->name, enable ? "M" : "Unm", bar->name, + bar->emulated_offset + index_offset, bar->emulated_offset + data_offset); + + /* Store start offsets, as well as end offsets to speed up operations. */ + bar->quirks.configwindow.offset[0].start = window_offset0; + bar->quirks.configwindow.offset[0].end = window_offset0 + 255; + bar->quirks.configwindow.offset[1].start = window_offset1; + bar->quirks.configwindow.offset[1].end = window_offset1 + 255; + + /* Enable or disable mapping. */ + vfio_quirk_capture_io(NULL, bar, bar->emulated_offset + index_offset, index_size, enable, + vfio_io_readb_fd, + vfio_io_readw_fd, + vfio_io_readl_fd, + vfio_quirk_configwindow_index_writeb, + vfio_quirk_configwindow_index_writew, + vfio_quirk_configwindow_index_writel); + vfio_quirk_capture_io(NULL, bar, bar->emulated_offset + data_offset, data_size, enable, + vfio_quirk_configwindow_data_readb, + vfio_quirk_configwindow_data_readw, + vfio_quirk_configwindow_data_readl, + vfio_quirk_configwindow_data_writeb, + vfio_quirk_configwindow_data_writew, + vfio_quirk_configwindow_data_writel); +} + +static uint8_t +vfio_quirk_iomirror_readb(uint16_t addr, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + + /* Read I/O port mirror from memory-mapped space. */ + uint8_t ret = vfio_mem_readb_fd(bar->emulated_offset + bar->quirks.iomirror.offset + addr, bar); +#ifdef ENABLE_VFIO_LOG + vfio_device_t *dev = bar->dev; + vfio_log_op("VFIO %s: I/O mirror: Read %02X from %04X (%08X)\n", dev->name, + ret, addr, bar->quirks.iomirror.offset + addr); +#endif + return ret; +} + +static uint16_t +vfio_quirk_iomirror_readw(uint16_t addr, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + + /* Read I/O port mirror from memory-mapped space. */ + uint16_t ret = vfio_mem_readw_fd(bar->emulated_offset + bar->quirks.iomirror.offset + addr, bar); +#ifdef ENABLE_VFIO_LOG + vfio_device_t *dev = bar->dev; + vfio_log_op("VFIO %s: I/O mirror: Read %04X from %04X (%08X)\n", dev->name, + ret, addr, bar->quirks.iomirror.offset + addr); +#endif + return ret; +} + +static uint32_t +vfio_quirk_iomirror_readl(uint16_t addr, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + + /* Read I/O port mirror from memory-mapped space. */ + uint32_t ret = vfio_mem_readl_fd(bar->emulated_offset + bar->quirks.iomirror.offset + addr, bar); +#ifdef ENABLE_VFIO_LOG + vfio_device_t *dev = bar->dev; + vfio_log_op("VFIO %s: I/O mirror: Read %08X from %04X (%08X)\n", dev->name, + ret, addr, bar->quirks.iomirror.offset + addr); +#endif + return ret; +} + +static void +vfio_quirk_iomirror_writeb(uint16_t addr, uint8_t val, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + + /* Write I/O port mirror to memory-mapped space. */ +#ifdef ENABLE_VFIO_LOG + vfio_device_t *dev = bar->dev; + vfio_log_op("VFIO %s: I/O mirror: Write %02X to %04X (%08X)\n", dev->name, + val, addr, bar->quirks.iomirror.offset + addr); +#endif + vfio_mem_writeb_fd(bar->emulated_offset + bar->quirks.iomirror.offset + addr, val, bar); +} + +static void +vfio_quirk_iomirror_writew(uint16_t addr, uint16_t val, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + + /* Write I/O port mirror to memory-mapped space. */ +#ifdef ENABLE_VFIO_LOG + vfio_device_t *dev = bar->dev; + vfio_log_op("VFIO %s: I/O mirror: Write %04X to %04X (%08X)\n", dev->name, + val, addr, bar->quirks.iomirror.offset + addr); +#endif + vfio_mem_writew_fd(bar->emulated_offset + bar->quirks.iomirror.offset + addr, val, bar); +} + +static void +vfio_quirk_iomirror_writel(uint16_t addr, uint32_t val, void *priv) +{ + vfio_region_t *bar = (vfio_region_t *) priv; + + /* Write I/O port mirror to memory-mapped space. */ +#ifdef ENABLE_VFIO_LOG + vfio_device_t *dev = bar->dev; + vfio_log_op("VFIO %s: I/O mirror: Write %08X to %04X (%08X)\n", dev->name, + val, addr, bar->quirks.iomirror.offset + addr); +#endif + vfio_mem_writel_fd(bar->emulated_offset + bar->quirks.iomirror.offset + addr, val, bar); +} + +static void +vfio_quirk_iomirror(vfio_device_t *dev, vfio_region_t *bar, + uint32_t offset, uint16_t base, uint16_t length, uint8_t enable) +{ + vfio_log("VFIO %s: %sapping I/O mirror for %s @ %08X\n", + dev->name, enable ? "M" : "Unm", bar->name, bar->emulated_offset + offset); + + /* Save I/O mirror offset, only one per BAR for now. */ + bar->quirks.iomirror.offset = offset; + + /* Add or remove quirk handler from port range. */ + if (enable) + io_sethandler(base, length, + bar->read ? vfio_quirk_iomirror_readb : NULL, + bar->read ? vfio_quirk_iomirror_readw : NULL, + bar->read ? vfio_quirk_iomirror_readl : NULL, + bar->write ? vfio_quirk_iomirror_writeb : NULL, + bar->write ? vfio_quirk_iomirror_writew : NULL, + bar->write ? vfio_quirk_iomirror_writel : NULL, + bar); + else + io_removehandler(base, length, + bar->read ? vfio_quirk_iomirror_readb : NULL, + bar->read ? vfio_quirk_iomirror_readw : NULL, + bar->read ? vfio_quirk_iomirror_readl : NULL, + bar->write ? vfio_quirk_iomirror_writeb : NULL, + bar->write ? vfio_quirk_iomirror_writew : NULL, + bar->write ? vfio_quirk_iomirror_writel : NULL, + bar); +} + +static uint8_t +vfio_quirk_ati3c3_readb(uint16_t addr, void *priv) +{ + vfio_device_t *dev = (vfio_device_t *) priv; + + /* Read high byte of the I/O BAR address. */ + uint8_t ret = dev->quirks.ati3c3.bar->emulated_offset >> 8; + vfio_log_op("VFIO %s: ATI 3C3: Read %02X\n", ret); + + return ret; +} + +static void +vfio_quirk_nvidiabar5(vfio_device_t *dev) +{ + /* Remap config window based on BAR enable status and the master/enable registers. */ + vfio_quirk_configwindow(dev, &dev->bars[5], 0x08, 4, 0x0c, 4, 0x1800, 0x88000, + dev->quirks.nvidiabar5.bar_enable && ((dev->quirks.nvidiabar5.master_enable & 0x0000000100000001) == 0x0000000100000001)); +} + +static void +vfio_quirk_nvidiabar5_writeb(uint16_t addr, uint8_t val, void *priv) +{ + vfio_device_t *dev = (vfio_device_t *) priv; + + /* Write master/enable registers. */ + vfio_log_op("VFIO %s: NVIDIA BAR 5: Write [%d] %02X\n", + dev->name, addr & 7, val); + uint8_t offset = (addr & 7) << 3; + dev->quirks.nvidiabar5.master_enable &= ~(0x00000000000000ff << offset); + dev->quirks.nvidiabar5.master_enable |= val << offset; + + /* Update window to account for changes in master/enable registers. */ + vfio_quirk_nvidiabar5(dev); + + /* Cascade to the main handler. */ + vfio_io_writeb_fd(addr, val, &dev->bars[5]); +} + +static void +vfio_quirk_nvidiabar5_writew(uint16_t addr, uint16_t val, void *priv) +{ + vfio_device_t *dev = (vfio_device_t *) priv; + + /* Write master/enable registers. */ + vfio_log_op("VFIO %s: NVIDIA BAR 5: Write [%d] %04X\n", + dev->name, addr & 7, val); + uint8_t offset = (addr & 6) << 3; + dev->quirks.nvidiabar5.master_enable &= ~(0x000000000000ffff << offset); + dev->quirks.nvidiabar5.master_enable |= val << offset; + + /* Update window to account for changes in master/enable registers. */ + vfio_quirk_nvidiabar5(dev); + + /* Cascade to the main handler. */ + vfio_io_writew_fd(addr, val, &dev->bars[5]); +} + +static void +vfio_quirk_nvidiabar5_writel(uint16_t addr, uint32_t val, void *priv) +{ + vfio_device_t *dev = (vfio_device_t *) priv; + + /* Write master/enable registers. */ + vfio_log_op("VFIO %s: NVIDIA BAR 5: Write [%d] %08X\n", + dev->name, addr & 7, val); + uint8_t offset = (addr & 4) << 3; + dev->quirks.nvidiabar5.master_enable &= ~(0x00000000ffffffff << offset); + dev->quirks.nvidiabar5.master_enable |= val << offset; + + /* Update window to account for changes in master/enable registers. */ + vfio_quirk_nvidiabar5(dev); + + /* Cascade to the main handler. */ + vfio_io_writel_fd(addr, val, &dev->bars[5]); +} + +static uint8_t +vfio_quirk_nvidia3d0_state_readb(uint16_t addr, void *priv) +{ + vfio_device_t *dev = (vfio_device_t *) priv; + + /* Reset state on read. */ + dev->quirks.nvidia3d0.state = NVIDIA_3D0_NONE; + vfio_log_op("VFIO %s: NVIDIA 3D0: Switching to NONE state (byte read)\n", dev->name); + + /* Cascade to the main handler. */ + return vfio_io_readb_fd(addr, &dev->vga_io_hi); +} + +static uint16_t +vfio_quirk_nvidia3d0_state_readw(uint16_t addr, void *priv) +{ + vfio_device_t *dev = (vfio_device_t *) priv; + + /* Reset state on read. */ + dev->quirks.nvidia3d0.state = NVIDIA_3D0_NONE; + vfio_log_op("VFIO %s: NVIDIA 3D0: Switching to NONE state (word read)\n", dev->name); + + /* Cascade to the main handler. */ + return vfio_io_readw_fd(addr, &dev->vga_io_hi); +} + +static uint32_t +vfio_quirk_nvidia3d0_state_readl(uint16_t addr, void *priv) +{ + vfio_device_t *dev = (vfio_device_t *) priv; + + /* Reset state on read. */ + dev->quirks.nvidia3d0.state = NVIDIA_3D0_NONE; + vfio_log_op("VFIO %s: NVIDIA 3D0: Switching to NONE state (dword read)\n", dev->name); + + /* Cascade to the main handler. */ + return vfio_io_readl_fd(addr, &dev->vga_io_hi); +} + +static void +vfio_quirk_nvidia3d0_state_writeb(uint16_t addr, uint8_t val, void *priv) +{ + vfio_device_t *dev = (vfio_device_t *) priv; + + /* Commands don't fit in a byte; just reset state and move on. */ + dev->quirks.nvidia3d0.state = NVIDIA_3D0_NONE; + vfio_log_op("VFIO %s: NVIDIA 3D0: Switching to NONE state (byte write)\n", dev->name); + + /* Cascade to the main handler. */ + vfio_io_writeb_fd(addr, val, &dev->vga_io_hi); +} + +static void +vfio_quirk_nvidia3d0_state_writew(uint16_t addr, uint16_t val, void *priv) +{ + vfio_device_t *dev = (vfio_device_t *) priv; + + uint8_t prev_state = dev->quirks.nvidia3d0.state; + dev->quirks.nvidia3d0.state = NVIDIA_3D0_NONE; + + /* Interpret NVIDIA commands. */ + switch (val) { + case 0x338: + if (prev_state == NVIDIA_3D0_NONE) { + dev->quirks.nvidia3d0.state = NVIDIA_3D0_SELECT; + vfio_log_op("VFIO %s: NVIDIA 3D0: Switching to SELECT state (word write)\n", dev->name); + } + break; + + case 0x538: + if (prev_state == NVIDIA_3D0_WINDOW) { + dev->quirks.nvidia3d0.state = NVIDIA_3D0_READ; + vfio_log_op("VFIO %s: NVIDIA 3D0: Switching to READ state (word write)\n", dev->name); + } + break; + + case 0x738: + if (prev_state == NVIDIA_3D0_WINDOW) { + dev->quirks.nvidia3d0.state = NVIDIA_3D0_WRITE; + vfio_log_op("VFIO %s: NVIDIA 3D0: Switching to WRITE state (word write)\n", dev->name); + } + break; + } + + /* Cascade to the main handler. */ + vfio_io_writew_fd(addr, val, &dev->vga_io_hi); +} + +static void +vfio_quirk_nvidia3d0_state_writel(uint16_t addr, uint32_t val, void *priv) +{ + vfio_device_t *dev = (vfio_device_t *) priv; + + uint8_t prev_state = dev->quirks.nvidia3d0.state; + dev->quirks.nvidia3d0.state = NVIDIA_3D0_NONE; + + /* Interpret NVIDIA commands. */ + switch (val) { + case 0x338: + if (prev_state == NVIDIA_3D0_NONE) { + dev->quirks.nvidia3d0.state = NVIDIA_3D0_SELECT; + vfio_log_op("VFIO %s: NVIDIA 3D0: Switching to SELECT state (dword write)\n", dev->name); + } + break; + + case 0x538: + if (prev_state == NVIDIA_3D0_WINDOW) { + dev->quirks.nvidia3d0.state = NVIDIA_3D0_READ; + vfio_log_op("VFIO %s: NVIDIA 3D0: Switching to READ state (dword write)\n", dev->name); + } + break; + + case 0x738: + if (prev_state == NVIDIA_3D0_WINDOW) { + dev->quirks.nvidia3d0.state = NVIDIA_3D0_WRITE; + vfio_log_op("VFIO %s: NVIDIA 3D0: Switching to WRITE state (dword write)\n", dev->name); + } + break; + } + + /* Cascade to the main handler. */ + vfio_io_writel_fd(addr, val, &dev->vga_io_hi); +} + +static uint8_t +vfio_quirk_nvidia3d0_data_readb(uint16_t addr, void *priv) +{ + vfio_device_t *dev = (vfio_device_t *) priv; + + /* Cascade to the main handler. */ + uint8_t prev_state = dev->quirks.nvidia3d0.state; + uint8_t ret = vfio_io_readb_fd(addr, &dev->vga_io_hi); + dev->quirks.nvidia3d0.state = NVIDIA_3D0_NONE; + + /* Read configuration register if part of the main PCI configuration space. */ + if ((prev_state == NVIDIA_3D0_READ) && (((dev->quirks.nvidia3d0.index & 0xffffff00) == 0x00001800) || ((dev->quirks.nvidia3d0.index & 0xffffff00) == 0x00088000))) { + ret = vfio_config_readb(0, dev->quirks.nvidia3d0.index, dev); + vfio_log_op("VFIO %s: NVIDIA 3D0: Read %02X from index %08X\n", dev->name, + ret, dev->quirks.nvidia3d0.index); + } + + return ret; +} + +static uint16_t +vfio_quirk_nvidia3d0_data_readw(uint16_t addr, void *priv) +{ + vfio_device_t *dev = (vfio_device_t *) priv; + + /* Cascade to the main handler. */ + uint8_t prev_state = dev->quirks.nvidia3d0.state; + uint16_t ret = vfio_io_readw_fd(addr, &dev->vga_io_hi); + dev->quirks.nvidia3d0.state = NVIDIA_3D0_NONE; + + /* Read configuration register if part of the main PCI configuration space. */ + if ((prev_state == NVIDIA_3D0_READ) && (((dev->quirks.nvidia3d0.index & 0xffffff00) == 0x00001800) || ((dev->quirks.nvidia3d0.index & 0xffffff00) == 0x00088000))) { + ret = vfio_config_readw(0, dev->quirks.nvidia3d0.index, dev); + vfio_log_op("VFIO %s: NVIDIA 3D0: Read %04X from index %08X\n", dev->name, + ret, dev->quirks.nvidia3d0.index); + } + + return ret; +} + +static uint32_t +vfio_quirk_nvidia3d0_data_readl(uint16_t addr, void *priv) +{ + vfio_device_t *dev = (vfio_device_t *) priv; + + /* Cascade to the main handler. */ + uint8_t prev_state = dev->quirks.nvidia3d0.state; + uint32_t ret = vfio_io_readl_fd(addr, &dev->vga_io_hi); + dev->quirks.nvidia3d0.state = NVIDIA_3D0_NONE; + + /* Read configuration register if part of the main PCI configuration space. */ + if ((prev_state == NVIDIA_3D0_READ) && (((dev->quirks.nvidia3d0.index & 0xffffff00) == 0x00001800) || ((dev->quirks.nvidia3d0.index & 0xffffff00) == 0x00088000))) { + ret = vfio_config_readl(0, dev->quirks.nvidia3d0.index, dev); + vfio_log_op("VFIO %s: NVIDIA 3D0: Read %08X from index %08X\n", dev->name, + ret, dev->quirks.nvidia3d0.index); + } + + return ret; +} + +static void +vfio_quirk_nvidia3d0_data_writeb(uint16_t addr, uint8_t val, void *priv) +{ + vfio_device_t *dev = (vfio_device_t *) priv; + + uint8_t prev_state = dev->quirks.nvidia3d0.state; + dev->quirks.nvidia3d0.state = NVIDIA_3D0_NONE; + + if (prev_state == NVIDIA_3D0_SELECT) { + /* Write MMIO index. */ + dev->quirks.nvidia3d0.index = val; + dev->quirks.nvidia3d0.state = NVIDIA_3D0_WINDOW; + vfio_log_op("VFIO %s: NVIDIA 3D0: Write index %02X\n", dev->name, val); + } else if (prev_state == NVIDIA_3D0_WRITE) { + /* Write configuration register if part of the main PCI configuration space. */ + if (((dev->quirks.nvidia3d0.index & 0xffffff00) == 0x00001800) || ((dev->quirks.nvidia3d0.index & 0xffffff00) == 0x00088000)) { + /* Write configuration register. */ + vfio_log_op("VFIO %s: NVIDIA 3D0: Write %02X to index %08X\n", dev->name, + val, dev->quirks.nvidia3d0.index); + vfio_config_writeb(0, dev->quirks.nvidia3d0.index, val, dev); + return; + } + } + + /* Cascade to the main handler. */ + vfio_io_writeb_fd(addr, val, &dev->vga_io_hi); +} + +static void +vfio_quirk_nvidia3d0_data_writew(uint16_t addr, uint16_t val, void *priv) +{ + vfio_device_t *dev = (vfio_device_t *) priv; + + uint8_t prev_state = dev->quirks.nvidia3d0.state; + dev->quirks.nvidia3d0.state = NVIDIA_3D0_NONE; + + if (prev_state == NVIDIA_3D0_SELECT) { + /* Write MMIO index. */ + dev->quirks.nvidia3d0.index = val; + dev->quirks.nvidia3d0.state = NVIDIA_3D0_WINDOW; + vfio_log_op("VFIO %s: NVIDIA 3D0: Write index %04X\n", dev->name, val); + } else if (prev_state == NVIDIA_3D0_WRITE) { + /* Write configuration register if part of the main PCI configuration space. */ + if (((dev->quirks.nvidia3d0.index & 0xffffff00) == 0x00001800) || ((dev->quirks.nvidia3d0.index & 0xffffff00) == 0x00088000)) { + vfio_log_op("VFIO %s: NVIDIA 3D0: Write %04X to index %08X\n", dev->name, + val, dev->quirks.nvidia3d0.index); + vfio_config_writew(0, dev->quirks.nvidia3d0.index, val, dev); + return; + } + } + + /* Cascade to the main handler. */ + vfio_io_writew_fd(addr, val, &dev->vga_io_hi); +} + +static void +vfio_quirk_nvidia3d0_data_writel(uint16_t addr, uint32_t val, void *priv) +{ + vfio_device_t *dev = (vfio_device_t *) priv; + + uint8_t prev_state = dev->quirks.nvidia3d0.state; + dev->quirks.nvidia3d0.state = NVIDIA_3D0_NONE; + + if (prev_state == NVIDIA_3D0_SELECT) { + /* Write MMIO index. */ + dev->quirks.nvidia3d0.index = val; + dev->quirks.nvidia3d0.state = NVIDIA_3D0_WINDOW; + vfio_log_op("VFIO %s: NVIDIA 3D0: Write index %08X\n", dev->name, val); + } else if (prev_state == NVIDIA_3D0_WRITE) { + /* Write configuration register if part of the main PCI configuration space. */ + if (((dev->quirks.nvidia3d0.index & 0xffffff00) == 0x00001800) || ((dev->quirks.nvidia3d0.index & 0xffffff00) == 0x00088000)) { + /* Write configuration register. */ + vfio_log_op("VFIO %s: NVIDIA 3D0: Write %08X to index %08X\n", dev->name, + val, dev->quirks.nvidia3d0.index); + vfio_config_writel(0, dev->quirks.nvidia3d0.index, val, dev); + return; + } + } + + /* Cascade to the main handler. */ + vfio_io_writel_fd(addr, val, &dev->vga_io_hi); +} + +static void +vfio_quirk_remap(vfio_device_t *dev, vfio_region_t *bar, uint8_t enable) +{ + /* Read vendor ID. */ + uint16_t vendor; + if (pread(dev->config.fd, &vendor, sizeof(vendor), dev->config.offset) != sizeof(vendor)) + vendor = 0x0000; + + int i, j; + switch (vendor) { + case 0x1002: /* ATI */ + i = (vfio_bar_gettype(dev, &dev->bars[1]) == 0x01) && (dev->bars[1].size >= 256); + j = (vfio_bar_gettype(dev, &dev->bars[4]) == 0x01) && (dev->bars[4].size >= 256); + + /* ATI/AMD cards report the I/O BAR's high byte on port 3C3, and according + to the Red Hat slide deck, this is used for VBIOS bootstrapping purposes. + This I/O BAR can be either 1 or 4, so we probe which one it is. If unsure + (shouldn't really happen), pick 1 which is mostly used by older cards. */ + if ((bar == &dev->vga_io_hi) && (i || j)) { + dev->quirks.ati3c3.bar = (j && !i) ? &dev->bars[4] : &dev->bars[1]; + vfio_log("VFIO %s: %sapping ATI 3C3 quirk (BAR %d)\n", dev->name, + enable ? "M" : "Unm", dev->quirks.ati3c3.bar->bar_id); + vfio_quirk_capture_io(dev, bar, 0x3c3, 1, enable, + vfio_quirk_ati3c3_readb, NULL, NULL, + NULL, NULL, NULL); + } + + /* BAR 2 configuration space mirror, and BAR 1/4 configuration space window. */ + if (j && !i) { + /* QEMU only enables the mirror here if BAR 2 is 64-bit capable. */ + if ((bar->bar_id == 2) && ((vfio_config_readb(0, 0x18, dev) & 0x07) == 0x04)) + vfio_quirk_configmirror(dev, bar, 0x4000, 0, enable); + else if (bar->bar_id == 4) + vfio_quirk_configwindow(dev, bar, 0x00, 4, 0x04, 4, 0x4000, 0x4000, enable); + } else { + if (bar->bar_id == 2) + vfio_quirk_configmirror(dev, bar, 0xf00, 0, enable); + else if (bar->bar_id == 1) + vfio_quirk_configwindow(dev, bar, 0x00, 4, 0x04, 4, 0xf00, 0xf00, enable); + } + break; + + case 0x1023: /* Trident */ + /* Mirror TGUI acceleration port range to memory-mapped space, since the PCI bridge + VGA decode policy doesn't allow it to be forwarded directly to the real card. */ + if ((bar->bar_id == 1) && (vfio_bar_gettype(dev, bar) == 0x00) && (bar->size >= 65536)) { + /* Port range from vid_tgui9440.c */ + vfio_quirk_iomirror(dev, bar, 0, 0x2100, 256, enable); + } + break; + + case 0x10de: /* NVIDIA */ + /* BAR 0 configuration space mirrors. */ + if ((bar->bar_id == 0) && (vfio_bar_gettype(dev, bar) == 0x00)) { + vfio_quirk_configmirror(dev, bar, 0x1800, 0, enable); + vfio_quirk_configmirror(dev, bar, 0x88000, 1, enable); + } + + /* BAR 5 configuration space window. */ + if ((bar->bar_id == 5) && (vfio_bar_gettype(dev, bar) == 0x01)) { + vfio_log("VFIO %s: %sapping NVIDIA BAR 5 quirk\n", dev->name, enable ? "M" : "Unm"); + vfio_quirk_capture_io(dev, bar, bar->emulated_offset, 8, enable, + vfio_io_readb_fd, + vfio_io_readw_fd, + vfio_io_readl_fd, + vfio_quirk_nvidiabar5_writeb, + vfio_quirk_nvidiabar5_writew, + vfio_quirk_nvidiabar5_writel); + + /* Update window to account for changes in BAR enable status. */ + dev->quirks.nvidiabar5.bar_enable = enable; + vfio_quirk_nvidiabar5(dev); + } + + /* Port 3D0 configuration space window. */ + if ((bar == &dev->vga_io_hi) && dev->bars[1].size) { + vfio_log("VFIO %s: %sapping NVIDIA 3D0 quirk\n", dev->name, enable ? "M" : "Unm"); + vfio_quirk_capture_io(dev, bar, 0x3d0, 1, enable, + vfio_quirk_nvidia3d0_data_readb, + vfio_quirk_nvidia3d0_data_readw, + vfio_quirk_nvidia3d0_data_readl, + vfio_quirk_nvidia3d0_data_writeb, + vfio_quirk_nvidia3d0_data_writew, + vfio_quirk_nvidia3d0_data_writel); + vfio_quirk_capture_io(dev, bar, 0x3d4, 1, enable, + vfio_quirk_nvidia3d0_state_readb, + vfio_quirk_nvidia3d0_state_readw, + vfio_quirk_nvidia3d0_state_readl, + vfio_quirk_nvidia3d0_state_writeb, + vfio_quirk_nvidia3d0_state_writew, + vfio_quirk_nvidia3d0_state_writel); + } + break; + + case 0x5333: /* S3 */ + /* Mirror enhanced command port ranges to memory-mapped space, since the PCI bridge + VGA decode policy doesn't allow those to be forwarded directly to the real card. */ + if (vfio_bar_gettype(dev, &dev->bars[0]) != 0x00) + break; + if ((dev->bars[0].size == 33554432) && (dev->bar_count == 1)) { + /* Older chips can only remap to VGA A0000. We can tell + those through BAR 0 being 32M and the only BAR. */ + if (bar == &dev->vga_mem) { + i = 0; + + /* Main port list from vid_s3.c */ + vfio_quirk_iomirror(dev, bar, i, 0x42e8, 2, enable); + vfio_quirk_iomirror(dev, bar, i, 0x46e8, 2, enable); + vfio_quirk_iomirror(dev, bar, i, 0x4ae8, 2, enable); + +s3_old_mmio: + vfio_quirk_iomirror(dev, bar, i, 0x82e8, 4, enable); + vfio_quirk_iomirror(dev, bar, i, 0x86e8, 4, enable); + vfio_quirk_iomirror(dev, bar, i, 0x8ae8, 4, enable); + vfio_quirk_iomirror(dev, bar, i, 0x8ee8, 4, enable); + vfio_quirk_iomirror(dev, bar, i, 0x92e8, 4, enable); + vfio_quirk_iomirror(dev, bar, i, 0x96e8, 4, enable); + + vfio_quirk_iomirror(dev, bar, i, 0x9ae8, 4, enable); + + vfio_quirk_iomirror(dev, bar, i, 0x9ee8, 2, enable); + vfio_quirk_iomirror(dev, bar, i, 0xa2e8, 4, enable); + vfio_quirk_iomirror(dev, bar, i, 0xa6e8, 4, enable); + vfio_quirk_iomirror(dev, bar, i, 0xaae8, 4, enable); + vfio_quirk_iomirror(dev, bar, i, 0xaee8, 4, enable); + + vfio_quirk_iomirror(dev, bar, i, 0xb2e8, 4, enable); + + vfio_quirk_iomirror(dev, bar, i, 0xb6e8, 2, enable); + vfio_quirk_iomirror(dev, bar, i, 0xbae8, 2, enable); + vfio_quirk_iomirror(dev, bar, i, 0xbee8, 2, enable); + vfio_quirk_iomirror(dev, bar, i, 0xe2e8, 2, enable); + + vfio_quirk_iomirror(dev, bar, i, 0xd2e8, 2, enable); + vfio_quirk_iomirror(dev, bar, i, 0xe6e8, 4, enable); + vfio_quirk_iomirror(dev, bar, i, 0xeae8, 4, enable); + vfio_quirk_iomirror(dev, bar, i, 0xeee8, 4, enable); + } + } else if ((dev->bars[0].size == 67108864) && (dev->bar_count == 1)) { + /* Trio64V+ and ViRGE chips can remap to BAR 0 + 16M. We can tell those through + BAR 0 being 64M = ((16M linear + 16M MMIO) * both endians) and the only BAR. */ + if (bar->bar_id == 0) { + i = 0x1000000; /* 16M MMIO offset */ + +s3_new_mmio: /* There's a configuration space mirror in here as well. */ + vfio_quirk_configmirror(dev, bar, i + 0x8000, 0, enable); + + /* Subsystem Control/Status and Advanced Function Control. */ + vfio_quirk_iomirror(dev, bar, i + 0x8504 - 0x42e8, 0x42e8, 2, enable); + vfio_quirk_iomirror(dev, bar, i + 0x850c - 0x4ae8, 0x4ae8, 2, enable); + + /* The rest maps exactly as older chips. */ + goto s3_old_mmio; + } + } else if ((dev->bars[0].size >= 524288) && (vfio_bar_gettype(dev, &dev->bars[1]) == 0x00)) { + /* Savage chips break the linear framebuffer out to + BAR 1+, eliminating the 16M MMIO offset from BAR 0. */ + if (bar->bar_id == 0) { + i = 0; + goto s3_new_mmio; + } + } + break; + } +} + +static uint8_t +vfio_bar_gettype(vfio_device_t *dev, vfio_region_t *bar) +{ + /* Read and store BAR type from device if unknown. */ + if (bar->type == 0xff) { + if (pread(dev->config.fd, &bar->type, sizeof(bar->type), + dev->config.offset + 0x10 + (bar->bar_id << 2)) + == sizeof(bar->type)) + bar->type &= 0x01; + else + bar->type = 0xff; + } + + /* Return stored BAR type. */ + return bar->type; +} + +static void +vfio_bar_remap(vfio_device_t *dev, vfio_region_t *bar, uint32_t new_offset) +{ + vfio_log("VFIO %s: bar_remap(%s, %08X)\n", dev->name, bar->name, new_offset); + + /* Act according to the BAR type. */ + uint8_t bar_type = vfio_bar_gettype(dev, bar); + if (bar_type == 0x00) { /* Memory BAR */ + if (bar->emulated_offset) { + vfio_log("VFIO %s: Unmapping %s memory @ %08X-%08X\n", dev->name, + bar->name, bar->emulated_offset, bar->emulated_offset + bar->size - 1); + + /* Unmap any quirks. */ + vfio_quirk_remap(dev, bar, 0); + + /* Disable memory mapping. */ + mem_mapping_disable(&bar->mem_mapping); + + /* Disable MSI-X table and PBA mappings if applicable to this BAR. */ + if (dev->irq.msix.table_bar == bar->bar_id) + mem_mapping_disable(&dev->irq.msix.table_mapping); + if (dev->irq.msix.pba_bar == bar->bar_id) + mem_mapping_disable(&dev->irq.msix.pba_mapping); + } + + bar->mmap_precalc = bar->mmap_base - new_offset; + /* Expansion ROM requires both ROM enable and memory enable. */ + if (((bar->bar_id != 0xff) || dev->rom_enabled) && dev->mem_enabled && new_offset) { + vfio_log("VFIO %s: Mapping %s memory @ %08X-%08X\n", dev->name, + bar->name, new_offset, new_offset + bar->size - 1); + + /* Enable memory mapping. */ + if (bar->mmap_base) /* mmap available */ + mem_mapping_set_p(&bar->mem_mapping, bar->mmap_precalc); + mem_mapping_set_addr(&bar->mem_mapping, new_offset, bar->size); + + /* Map any quirks. */ + vfio_quirk_remap(dev, bar, 1); + + /* Enable MSI-X table and PBA mappings if applicable to this BAR. */ + if (dev->irq.msix.table_bar == bar->bar_id) { + dev->irq.msix.table_offset_precalc = new_offset + dev->irq.msix.table_offset; + mem_mapping_set_addr(&dev->irq.msix.table_mapping, + dev->irq.msix.table_offset_precalc, + dev->irq.msix.table_size); + } + if (dev->irq.msix.pba_bar == bar->bar_id) { + dev->irq.msix.pba_offset_precalc = new_offset + dev->irq.msix.pba_offset; + mem_mapping_set_addr(&dev->irq.msix.pba_mapping, + dev->irq.msix.pba_offset_precalc, + dev->irq.msix.pba_size); + } + } + } else if (bar_type == 0x01) { /* I/O BAR */ + if (bar->emulated_offset) { + vfio_log("VFIO %s: Unmapping %s I/O @ %04X-%04X\n", dev->name, + bar->name, bar->emulated_offset, bar->emulated_offset + bar->size - 1); + + /* Unmap any quirks. */ + vfio_quirk_remap(dev, bar, 0); + + /* Disable I/O mapping. */ + if (bar->mmap_base) /* mmap available */ + io_removehandler(bar->emulated_offset, bar->size, + bar->read ? vfio_io_readb_mm : NULL, + bar->read ? vfio_io_readw_mm : NULL, + bar->read ? vfio_io_readl_mm : NULL, + bar->write ? vfio_io_writeb_mm : NULL, + bar->write ? vfio_io_writew_mm : NULL, + bar->write ? vfio_io_writel_mm : NULL, + bar->mmap_precalc); + else /* mmap not available */ + io_removehandler(bar->emulated_offset, bar->size, + bar->read ? vfio_io_readb_fd : NULL, + bar->read ? vfio_io_readw_fd : NULL, + bar->read ? vfio_io_readl_fd : NULL, + bar->write ? vfio_io_writeb_fd : NULL, + bar->write ? vfio_io_writew_fd : NULL, + bar->write ? vfio_io_writel_fd : NULL, + bar); + } + + bar->mmap_precalc = bar->mmap_base - new_offset; + if (dev->io_enabled && new_offset) { + vfio_log("VFIO %s: Mapping %s I/O @ %04X-%04X\n", dev->name, + bar->name, new_offset, new_offset + bar->size - 1); + + /* Enable I/O mapping. */ + if (bar->mmap_base) /* mmap available */ + io_sethandler(new_offset, bar->size, + bar->read ? vfio_io_readb_mm : NULL, + bar->read ? vfio_io_readw_mm : NULL, + bar->read ? vfio_io_readl_mm : NULL, + bar->write ? vfio_io_writeb_mm : NULL, + bar->write ? vfio_io_writew_mm : NULL, + bar->write ? vfio_io_writel_mm : NULL, + bar->mmap_precalc); + else /* mmap not available */ + io_sethandler(new_offset, bar->size, + bar->read ? vfio_io_readb_fd : NULL, + bar->read ? vfio_io_readw_fd : NULL, + bar->read ? vfio_io_readl_fd : NULL, + bar->write ? vfio_io_writeb_fd : NULL, + bar->write ? vfio_io_writew_fd : NULL, + bar->write ? vfio_io_writel_fd : NULL, + bar); + + /* Map any quirks. */ + vfio_quirk_remap(dev, bar, 1); + } + } + + /* Set new emulated and precalculated offsets. + The precalculated offsets speed up read/write operations. */ + bar->emulated_offset = new_offset; + bar->precalc_offset = bar->offset - new_offset; +} + +static uint32_t +ceilpow2(uint32_t size) +{ + uint32_t pow_size = 1 << log2i(size); + if (pow_size < size) + return pow_size << 1; + return pow_size; +} + +static uint8_t +vfio_config_readb(int func, int addr, void *priv) +{ + vfio_device_t *dev = (vfio_device_t *) priv; + if (func) + return 0xff; + + intx_high = 0; + + /* Read register from device. */ + addr &= 0xff; + uint8_t ret; + if (pread(dev->config.fd, &ret, 1, dev->config.offset + addr) != 1) { + vfio_log("VFIO %s: config_readb(%d, %02X) failed\n", dev->name, + func, addr); + return 0xff; + } + + /* Change value accordingly. */ + uint8_t bar_id, offset, new; + switch (addr) { + case 0x10 ... 0x27: /* BARs */ + /* Stop if this BAR is absent. */ + bar_id = (addr - 0x10) >> 2; + if (!dev->bars[bar_id].read && !dev->bars[bar_id].write) { + ret = 0x00; + break; + } + + /* Mask off and insert static bits. */ + offset = (addr & 3) << 3; + new = dev->bars[bar_id].emulated_offset >> offset; + if (!offset) { + switch (vfio_bar_gettype(dev, &dev->bars[bar_id])) { + case 0x00: /* Memory BAR */ + new = (new & ~0x07) | (ret & 0x07); + break; + + case 0x01: /* I/O BAR */ + new = (new & ~0x03) | (ret & 0x03); + break; + } + } + ret = new; + break; + + case 0x30 ... 0x33: /* Expansion ROM */ + /* Stop if the ROM is absent. */ + if (!dev->rom.read) { + ret = 0x00; + break; + } + + /* Mask off and insert ROM enable bit. */ + offset = (addr & 3) << 3; + ret = dev->rom.emulated_offset >> offset; + if (!offset) + ret = (ret & ~0x01) | dev->rom_enabled; + break; + + default: /* other (capabilities) */ + if (dev->msi_cap && (addr >= dev->msi_cap)) { /* MSI */ + /* Adjust register offset to account for different structure levels. */ + offset = addr - dev->msi_cap; + if (!(dev->irq.msi.ctl & 0x0080) && (offset >= 0x08)) + offset += 4; + switch (offset) { + case 0x02 ... 0x03: /* Message Control */ + offset = (offset - 0x02) << 3; + ret = dev->irq.msi.ctl >> offset; + goto end; + + case 0x04 ... 0x07: /* Message Address */ + offset = (offset - 0x04) << 3; + ret = dev->irq.msi.address >> offset; + goto end; + + case 0x08 ... 0x0b: /* Message Upper Address */ + offset = (offset - 0x08) << 3; + ret = dev->irq.msi.address_upper >> offset; + goto end; + + case 0x0c ... 0x0d: /* Message Data */ + offset = (offset - 0x0c) << 3; + ret = dev->irq.msi.data >> offset; + goto end; + + case 0x10 ... 0x13: /* Mask Bits */ + if (dev->irq.msi.ctl & 0x0100) { + offset = (offset - 0x10) << 3; + ret = dev->irq.msi.mask >> offset; + goto end; + } + break; + + case 0x14 ... 0x17: /* Pending Bits */ + if (dev->irq.msi.ctl & 0x0100) { + offset = (offset - 0x14) << 3; + ret = dev->irq.msi.pending >> offset; + goto end; + } + break; + } + } + if (dev->msix_cap && (addr >= dev->msix_cap)) { /* MSI-X */ + offset = addr - dev->msix_cap; + switch (offset) { + case 0x02 ... 0x03: /* Message Control */ + offset = (offset - 0x02) << 3; + ret = dev->irq.msix.ctl >> offset; + goto end; + } + } +end: + break; + } + + vfio_log("VFIO %s: config_readb(%02X) = %02X\n", dev->name, + addr, ret); + + return ret; +} + +static uint16_t +vfio_config_readw(int func, int addr, void *priv) +{ + return vfio_config_readb(func, addr, priv) | (vfio_config_readb(func, addr + 1, priv) << 8); +} + +static uint32_t +vfio_config_readl(int func, int addr, void *priv) +{ + return vfio_config_readb(func, addr, priv) | (vfio_config_readb(func, addr + 1, priv) << 8) | (vfio_config_readb(func, addr + 2, priv) << 16) | (vfio_config_readb(func, addr + 3, priv) << 24); +} + +static void +vfio_config_writeb(int func, int addr, uint8_t val, void *priv) +{ + vfio_device_t *dev = (vfio_device_t *) priv; + if (func) + return; + + addr &= 0xff; + vfio_log("VFIO %s: config_writeb(%02X, %02X)\n", dev->name, addr, val); + + intx_high = 0; + + /* VFIO should block anything we shouldn't write to, such as BARs. */ + (void) !pwrite(dev->config.fd, &val, 1, dev->config.offset + addr); + + /* Act on some written values. */ + uint8_t new_mem_enabled; + uint8_t new_io_enabled; + uint8_t bar_id; + uint8_t offset; + uint32_t new_value; + uint64_t val64; + + switch (addr) { + case 0x04: /* Command */ + /* Determine new memory and I/O enable states. */ + new_mem_enabled = !!(val & PCI_COMMAND_MEM); + new_io_enabled = !!(val & PCI_COMMAND_IO); + + vfio_log("VFIO %s: Command Memory[%d] I/O[%d]\n", dev->name, + new_mem_enabled, new_io_enabled); + + /* Remap regions only if their respective enable bits have changed. */ + if (dev->mem_enabled ^ new_mem_enabled) { + /* Set new memory enable state. */ + dev->mem_enabled = new_mem_enabled; + + /* Remap memory BARs. */ + for (uint8_t i = 0; i < 6; i++) { + if (vfio_bar_gettype(dev, &dev->bars[i]) == 0x00) + vfio_bar_remap(dev, &dev->bars[i], dev->bars[i].emulated_offset); + } + + /* Remap ROM if present. */ + if (dev->rom.read) + vfio_bar_remap(dev, &dev->rom, dev->rom.emulated_offset); + + /* Remap VGA framebuffer region if present. */ + if (dev->vga_mem.bar_id) + vfio_bar_remap(dev, &dev->vga_mem, 0xa0000); + } + if (dev->io_enabled ^ new_io_enabled) { + /* Set new I/O enable state. */ + dev->io_enabled = new_io_enabled; + + /* Remap I/O BARs. */ + for (uint8_t i = 0; i < 6; i++) { + if (vfio_bar_gettype(dev, &dev->bars[i]) == 0x01) + vfio_bar_remap(dev, &dev->bars[i], dev->bars[i].emulated_offset); + } + + /* Remap VGA I/O regions if present. */ + if (dev->vga_io_lo.bar_id) { + vfio_bar_remap(dev, &dev->vga_io_lo, 0x3b0); + vfio_bar_remap(dev, &dev->vga_io_hi, 0x3c0); + } + } + break; + + case 0x10 ... 0x27: /* BARs */ + /* Stop if this BAR is absent. */ + bar_id = (addr - 0x10) >> 2; + if (!dev->bars[bar_id].read && !dev->bars[bar_id].write) + break; + + /* Mask off static bits. */ + offset = (addr & 3) << 3; + if (!offset) { + switch (vfio_bar_gettype(dev, &dev->bars[bar_id])) { + case 0x00: /* Memory BAR */ + val &= ~0x07; + break; + + case 0x01: /* I/O BAR */ + val &= ~0x03; + break; + } + } + + /* Remap BAR. */ + new_value = dev->bars[bar_id].emulated_offset & ~(0x000000ff << offset); + new_value |= val << offset; + new_value &= ~(ceilpow2(dev->bars[bar_id].size) - 1); + vfio_bar_remap(dev, &dev->bars[bar_id], new_value); + break; + + case 0x30 ... 0x33: /* Expansion ROM */ + /* Stop if the ROM is absent. */ + if (!dev->rom.read) + break; + + /* Set ROM enable bit. */ + offset = (addr & 3) << 3; + if (!offset) { + dev->rom_enabled = val & 0x01; + val &= 0xfe; + } + + /* Remap ROM. */ + new_value = (dev->rom.emulated_offset & ~(0x000000ff << offset)); + new_value |= val << offset; + new_value &= ~(ceilpow2(dev->rom.size) - 1); + vfio_bar_remap(dev, &dev->rom, new_value); + break; + + case 0x3d: /* Interrupt Pin */ + if (val != dev->irq.intx.pin) + vfio_irq_intx_setpin(dev); + break; + + default: /* other (capabilities) */ + if (dev->msi_cap && (addr >= dev->msi_cap)) { /* MSI */ + /* Adjust register offset to account for different structure levels. */ + offset = addr - dev->msi_cap; + if (!(dev->irq.msi.ctl & 0x0080) && (offset >= 0x08)) + offset += 4; + switch (offset) { + case 0x00 ... 0x01: /* Capability */ + goto end; + + case 0x02 ... 0x03: /* Message Control */ + offset = (offset - 0x02) << 3; + new_value = dev->irq.msi.ctl & ~(0x00ff << offset); + new_value |= val << offset; + + /* Enable or disable MSI if requested and not conflicting with MSI-X. */ + if (dev->irq.type != VFIO_PCI_MSIX_IRQ_INDEX) { + if (!(dev->irq.msi.ctl & 0x0001) && (new_value & 0x0001)) + vfio_irq_enable(dev, VFIO_PCI_MSI_IRQ_INDEX); + else if ((dev->irq.msi.ctl & 0x0001) && !(new_value & 0x0001)) + vfio_irq_msi_disable(dev); + } + + /* Update control register. */ + dev->irq.msi.ctl = (new_value & 0x0071) | (dev->irq.msi.ctl & 0xff8e); + + /* Update enabled vector count and mask. */ + dev->irq.msi.vector_enable_count = MIN(1 << ((dev->irq.msi.ctl >> 1) & 3), dev->irq.msi.vector_count); + dev->irq.msi.vector_enable_mask = dev->irq.msi.vector_enable_count - 1; + goto end; + + case 0x04 ... 0x07: /* Message Address */ + offset = (offset - 0x04) << 3; + new_value = dev->irq.msi.address & ~(0x000000ff << offset); + new_value |= val << offset; + dev->irq.msi.address = new_value & 0xfffffffc; + goto end; + + case 0x08 ... 0x0b: /* Message Upper Address */ + offset = (offset - 0x08) << 3; + new_value = dev->irq.msi.address_upper & ~(0x000000ff << offset); + new_value |= val << offset; + dev->irq.msi.address_upper = new_value; + goto end; + + case 0x0c ... 0x0d: /* Message Data */ + offset = (offset - 0x0c) << 3; + new_value = dev->irq.msi.data & ~(0x00ff << offset); + new_value |= val << offset; + dev->irq.msi.data = new_value; + goto end; + + case 0x0e ... 0x0f: /* Reserved */ + case 0x14 ... 0x17: /* Pending Bits */ + if (dev->irq.msi.ctl & 0x0100) + goto end; + break; + + case 0x10 ... 0x13: /* Mask Bits */ + if (dev->irq.msi.ctl & 0x0100) { + offset = (offset - 0x10) << 3; + new_value = dev->irq.msi.mask & ~(0x000000ff << offset); + new_value |= val << offset; + dev->irq.msi.mask = new_value; + + /* Service any unmasked pending interrupts if MSI is enabled. */ + if (dev->irq.msi.ctl & 0x0001) { + new_value = ~new_value; + val64 = 1; + for (uint8_t i = 0; i < dev->irq.msi.vector_enable_count; i++) { + if (dev->irq.msi.pending & ((1 << i) & new_value)) + (void) !write(dev->irq.vectors[i].fd, &val64, sizeof(val64)); + } + dev->irq.msi.pending &= new_value; + } + + goto end; + } + break; + } + } + if (dev->msix_cap && (addr >= dev->msix_cap)) { /* MSI-X */ + offset = addr - dev->msix_cap; + switch (offset) { + case 0x00 ... 0x01: /* Capability */ + case 0x04 ... 0x0b: /* Table/PBA Offset */ + goto end; + + case 0x02 ... 0x03: /* Message Control */ + offset = (offset - 0x02) << 3; + new_value = dev->irq.msix.ctl & ~(0x00ff << offset); + new_value |= val << offset; + + /* Enable or disable MSI-X if requested. */ + if (!(dev->irq.msix.ctl & 0x8000) && (new_value & 0x8000)) + vfio_irq_enable(dev, VFIO_PCI_MSIX_IRQ_INDEX); + else if ((dev->irq.msix.ctl & 0x8000) && !(new_value & 0x8000)) + vfio_irq_msix_disable(dev); + + /* Update control register. */ + dev->irq.msix.ctl = (new_value & 0xc000) | (dev->irq.msix.ctl & 0x3fff); + + /* Service any unmasked pending interrupts if MSI-X + is enabled and the global mask bit was cleared. */ + if ((dev->irq.msix.ctl & 0xc000) == 0x8000) { + for (uint16_t i = 0x000c; i < dev->irq.msix.table_size; i += 0x0010) + vfio_irq_msix_updatemask(dev, i); + } + goto end; + } + } +end: + break; + } +} + +static void +vfio_config_writew(int func, int addr, uint16_t val, void *priv) +{ + vfio_config_writeb(func, addr, val, priv); + vfio_config_writeb(func, addr | 1, val >> 8, priv); +} + +static void +vfio_config_writel(int func, int addr, uint32_t val, void *priv) +{ + vfio_config_writeb(func, addr, val, priv); + vfio_config_writeb(func, addr | 1, val >> 8, priv); + vfio_config_writeb(func, addr | 2, val >> 16, priv); + vfio_config_writeb(func, addr | 3, val >> 24, priv); +} + +static void +vfio_irq_thread(void *priv) +{ + int nfds, i; + uint64_t buf; + struct epoll_event events[16]; + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), + .index = VFIO_PCI_INTX_IRQ_INDEX, + .start = 0, + .count = 1 + }; + vfio_device_t *dev; + vfio_irq_t *irq; + + vfio_log("VFIO: IRQ thread started\n"); + + while (epoll_fd >= 0) { + /* Wait for an interrupt to come in. */ + nfds = epoll_wait(epoll_fd, events, sizeof(events) / sizeof(events[0]), -1); + if (nfds < 0) { + vfio_log("VFIO %s: epoll_wait failed (%d)\n", errno); + break; + } + + /* Process all interrupts which came in. */ + for (i = 0; i < nfds; i++) { + /* Only handle read events. */ + if (!(events[i].events & EPOLLIN)) + continue; + + /* Get the IRQ and device structures for this interrupt. */ + irq = (vfio_irq_t *) events[i].data.ptr; + if (!irq) { + /* Do nothing if this is the wake eventfd, which has no data. */ + (void) !read(irq_thread_wake_fd, &buf, sizeof(buf)); + continue; + } + dev = irq->dev; + + /* Reset eventfd counter. */ + (void) !read(irq->fd, &buf, sizeof(buf)); + + /* Don't hang waiting for the timer if we're closing. */ + if (closing) + continue; + + /* Log VFIO IRQ type and vector. */ + vfio_log_op("VFIO %s: %s IRQ on vector %d\n", dev->name, + ((irq->type == VFIO_PCI_INTX_IRQ_INDEX) ? "INTx" : (((irq->type == VFIO_PCI_MSI_IRQ_INDEX) ? "MSI" : ((irq->type == VFIO_PCI_MSIX_IRQ_INDEX) ? "MSI-X" : NULL)))), + irq->vector); + + /* Perform pre-checks for specific IRQ types. */ + switch (irq->type) { + case VFIO_PCI_INTX_IRQ_INDEX: + /* Mask host IRQ. */ + irq_set.flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK; + ioctl(dev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); + break; + + case VFIO_PCI_MSI_IRQ_INDEX: + /* Ignore MSI if this vector is not enabled. */ + if (irq->vector >= dev->irq.msi.vector_enable_count) { + vfio_log_op("VFIO %s: MSI vector not enabled (%d >= %d)\n", dev->name, + irq->vector, dev->irq.msi.vector_enable_count); + continue; + } + + /* Ignore MSI if the upper 32 bits of a 64-bit address are non-zero. */ + if (dev->irq.msi.address_upper) { + vfio_log_op("VFIO %s: MSI 64-bit address %08X%08X\n", dev->name, + dev->irq.msi.address_upper, dev->irq.msi.address); + continue; + } + + /* Mark MSI as pending if this vector is masked through per-vector masking. */ + if (dev->irq.msi.mask & (1 << irq->vector)) { + vfio_log_op("VFIO %s: MSI masked\n", dev->name); + dev->irq.msi.pending |= 1 << irq->vector; + continue; + } + break; + + case VFIO_PCI_MSIX_IRQ_INDEX: + /* Ignore MSI-X if the upper 32 bits of a 64-bit address are non-zero. */ + if (*((uint32_t *) &dev->irq.msix.table[irq->msix_offset | 0x4])) { + vfio_log_op("VFIO %s: MSI-X 64-bit address %016X\n", dev->name, + *((uint64_t *) &dev->irq.msix.table[irq->msix_offset])); + continue; + } + + /* Mark MSI-X as pending if this vector or all vectors are masked. */ + if ((dev->irq.msix.ctl & 0x4000) || (dev->irq.msix.table[irq->msix_offset | 0xc] & 0x01)) { + vfio_log_op("VFIO %s: MSI-X masked\n", dev->name); + dev->irq.msix.pba[irq->vector >> 3] |= 1 << (irq->vector & 0x07); + continue; + } + break; + } + + /* Tell the timer to service this interrupt. */ + current_irq = irq; + + /* Wait for the timer to do its job. */ + thread_wait_event(irq_event, -1); + thread_reset_event(irq_event); + vfio_log_op("VFIO %s: IRQ serviced\n", dev->name); + + /* Unmask host IRQ if this is INTx. */ + if (irq->type == VFIO_PCI_INTX_IRQ_INDEX) { + irq_set.flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK; + ioctl(dev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); + } + } + + /* Pause if we were asked to. */ + thread_wait_event(irq_thread_resume, -1); + } + + /* We're done here. */ + vfio_log("VFIO: IRQ thread finished\n"); +} + +static void +vfio_irq_timer(void *priv) +{ + /* Schedule next run. */ + timer_on_auto(&irq_timer, 100.0); + + /* Stop if we're not servicing an IRQ at the moment. */ + if (!current_irq) + return; + vfio_device_t *dev = current_irq->dev; + + /* Act according to the IRQ type. */ + uint16_t val; + switch (current_irq->type) { + case VFIO_PCI_INTX_IRQ_INDEX: + if (!dev->irq.intx.raised) { /* rising edge */ + vfio_log_op("VFIO %s: Raising IRQ on pin INT%c\n", dev->name, + '@' + dev->irq.intx.pin); + + /* Raise IRQ. */ + pci_set_irq(dev->slot, dev->irq.intx.pin, &dev->irq.intx.state); + + /* Mark the IRQ as active, so that a BAR read/write can lower it. */ + dev->irq.intx.raised = intx_high = 1; + } else if (!intx_high) { /* falling edge */ + vfio_log_op("VFIO %s: Lowering IRQ on pin INT%c\n", dev->name, + '@' + dev->irq.intx.pin); + + /* Lower IRQ. */ + pci_clear_irq(dev->slot, dev->irq.intx.pin, &dev->irq.intx.state); + + /* Mark the IRQ as no longer high. */ + dev->irq.intx.raised = intx_high = 0; + + /* Allow the IRQ thread to be unblocked. */ + break; + } + + /* Don't unblock the IRQ thread unless otherwise stated. */ + return; + + case VFIO_PCI_MSI_IRQ_INDEX: + /* Insert the vector number into the value's lower bits. */ + val = (dev->irq.msi.data & ~dev->irq.msi.vector_enable_mask) | (current_irq->vector & dev->irq.msi.vector_enable_mask); + + /* Write value. */ + vfio_log_op("VFIO %s: Writing MSI value %04X to %04X\n", dev->name, val, dev->irq.msi.address); + mem_writew_phys(dev->irq.msi.address, val); + break; + + case VFIO_PCI_MSIX_IRQ_INDEX: + /* Write value. */ + vfio_log_op("VFIO %s: Writing MSI-X value %08X to %08X\n", dev->name, + *((uint32_t *) &dev->irq.msix.table[current_irq->msix_offset | 0x8]), + *((uint32_t *) &dev->irq.msix.table[current_irq->msix_offset])); + mem_writel_phys(*((uint32_t *) &dev->irq.msix.table[current_irq->msix_offset]), + *((uint32_t *) &dev->irq.msix.table[current_irq->msix_offset | 0x8])); + break; + } + + /* Unblock the IRQ thread. */ + current_irq = NULL; + thread_set_event(irq_event); +} + +static void +vfio_irq_disabletype(vfio_device_t *dev, int type) +{ + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), + .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER, + .index = type, + .start = 0, + .count = 0, + }; + ioctl(dev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); +} + +static void +vfio_irq_intx_disable(vfio_device_t *dev) +{ + /* Disable INTx on VFIO. */ + vfio_irq_disabletype(dev, VFIO_PCI_INTX_IRQ_INDEX); + + /* Clear pending interrupts. */ + dev->irq.intx.raised = intx_high = 0; + if (dev->irq.intx.pin) + pci_clear_irq(dev->slot, dev->irq.intx.pin, &dev->irq.intx.state); + + /* Disable interrupts altogether. */ + dev->irq.type = VFIO_PCI_NUM_IRQS; +} + +static void +vfio_irq_intx_setpin(vfio_device_t *dev) +{ + uint8_t val; + if (pread(dev->config.fd, &val, sizeof(val), dev->config.offset + 0x3d) == sizeof(val)) + dev->irq.intx.pin = val; + vfio_log("VFIO %s: IRQ pin is INT%c\n", dev->name, '@' + MIN(dev->irq.intx.pin, 'Z')); +} + +static void +vfio_irq_msi_disable(vfio_device_t *dev) +{ + /* Clear pending interrupts. */ + dev->irq.msi.pending = 0; + + /* Disable MSI on VFIO. */ + vfio_irq_disabletype(dev, VFIO_PCI_MSI_IRQ_INDEX); + + /* Re-enable INTx interrupts. */ + vfio_irq_enable(dev, VFIO_PCI_INTX_IRQ_INDEX); +} + +static void +vfio_irq_msix_disable(vfio_device_t *dev) +{ + /* Clear pending interrupts. */ + memset(dev->irq.msix.pba, 0, dev->irq.vector_count); + + /* Disable MSI-X on VFIO. */ + vfio_irq_disabletype(dev, VFIO_PCI_MSIX_IRQ_INDEX); + + /* Re-enable INTx interrupts. */ + vfio_irq_enable(dev, VFIO_PCI_INTX_IRQ_INDEX); +} + +static void +vfio_irq_msix_updatemask(vfio_device_t *dev, uint16_t offset) +{ + /* Service any unmasked pending interrupts. */ + if (((dev->irq.msix.ctl & 0xc000) == 0x8000) && !(dev->irq.msix.table[offset] & 0x01) && (dev->irq.msix.pba[offset >> 7] & (1 << (offset & 0x07)))) { + uint64_t val = 1; + (void) !write(dev->irq.vectors[offset >> 4].fd, &val, sizeof(val)); + dev->irq.msix.pba[offset >> 7] &= ~(1 << (offset & 0x07)); + } +} + +#define VFIO_RW_MSIX(length_char, val_type, val_slength) \ + static val_type \ + vfio_irq_msix_table_read##length_char(uint32_t addr, void *priv) \ + { \ + vfio_device_t *dev = (vfio_device_t *) priv; \ + val_type ret = dev->irq.msix.table[addr - dev->irq.msix.table_offset_precalc]; \ + vfio_log_op("[%08X:%04X] VFIO %s: msix_table_read" #length_char "(%08X) = %0" #val_slength "X\n", CS, cpu_state.pc, dev->name, addr, ret); \ + return ret; \ + } \ + \ + static void \ + vfio_irq_msix_table_write##length_char(uint32_t addr, val_type val, void *priv) \ + { \ + vfio_device_t *dev = (vfio_device_t *) priv; \ + vfio_log_op("[%08X:%04X] VFIO %s: msix_table_write" #length_char "(%08X, %0" #val_slength "X)\n", CS, cpu_state.pc, dev->name, addr, val); \ + uint16_t offset = addr - dev->irq.msix.table_offset_precalc; \ + dev->irq.msix.table[offset] = val; \ + if ((offset & 0x000f) == 0x000c) \ + vfio_irq_msix_updatemask(dev, offset); \ + } \ + \ + static val_type \ + vfio_irq_msix_pba_read##length_char(uint32_t addr, void *priv) \ + { \ + vfio_device_t *dev = (vfio_device_t *) priv; \ + val_type ret = dev->irq.msix.table[addr - dev->irq.msix.pba_offset_precalc]; \ + vfio_log_op("[%08X:%04X] VFIO %s: msix_pba_read" #length_char "(%08X) = %0" #val_slength "X\n", CS, cpu_state.pc, dev->name, addr, ret); \ + return ret; \ + } \ + \ + static void \ + vfio_irq_msix_pba_write##length_char(uint32_t addr, val_type val, void *priv) \ + { \ + vfio_device_t *dev = (vfio_device_t *) priv; \ + vfio_log_op("[%08X:%04X] VFIO %s: msix_pba_write" #length_char "(%08X, %0" #val_slength "X)\n", CS, cpu_state.pc, dev->name, addr, val); \ + } + +VFIO_RW_MSIX(b, uint8_t, 2) +VFIO_RW_MSIX(w, uint16_t, 4) +VFIO_RW_MSIX(l, uint32_t, 8) + +static void +vfio_irq_disable(vfio_device_t *dev) +{ + /* Do nothing if IRQs are already disabled. */ + if (dev->irq.type == VFIO_PCI_NUM_IRQS) + return; + vfio_log("VFIO %s: irq_disable(%d)\n", dev->name, dev->irq.type); + + /* Pause IRQ thread. */ + thread_reset_event(irq_thread_resume); + uint64_t val = 1; + (void) !write(irq_thread_wake_fd, &val, sizeof(val)); + + /* Always disable INTx after disabling MSI/MSI-X. */ + if (dev->irq.type == VFIO_PCI_MSIX_IRQ_INDEX) + vfio_irq_msix_disable(dev); + else if (dev->irq.type == VFIO_PCI_MSI_IRQ_INDEX) + vfio_irq_msi_disable(dev); + if (dev->irq.type == VFIO_PCI_INTX_IRQ_INDEX) + vfio_irq_intx_disable(dev); + + /* Invalidate all IRQ vectors. */ + if (dev->irq.vectors) { + for (int i = 0; i < dev->irq.vector_count; i++) { + if (dev->irq.vectors[i].fd >= 0) { + /* Remove eventfd from epoll. */ + epoll_ctl(epoll_fd, EPOLL_CTL_DEL, dev->irq.vectors[i].fd, NULL); + close(dev->irq.vectors[i].fd); + } + } + free(dev->irq.vectors); + dev->irq.vectors = NULL; + dev->irq.vector_count = 0; + } + + /* Resume IRQ thread. */ + thread_set_event(irq_thread_resume); +} + +static void +vfio_irq_enable(vfio_device_t *dev, int type) +{ + /* Disable any existing IRQs. */ + vfio_irq_disable(dev); + + vfio_log("VFIO %s: irq_enable(%d)\n", dev->name, type); + + /* Determine the number of vectors needed. */ + switch (type) { + case VFIO_PCI_INTX_IRQ_INDEX: + /* Only one vector needed. */ + dev->irq.vector_count = 1; + break; + + case VFIO_PCI_MSI_IRQ_INDEX: + /* Up to the number of vectors read during init is needed. */ + dev->irq.vector_count = dev->irq.msi.vector_count; + break; + + case VFIO_PCI_MSIX_IRQ_INDEX: + /* The number of vectors read during init is needed. */ + dev->irq.vector_count = dev->irq.msix.vector_count; + break; + } + + /* Prepare structure for enabling the interrupt type. */ + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set) + (sizeof(int32_t) * dev->irq.vector_count), + .flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER, + .index = type, + .start = 0, + .count = dev->irq.vector_count + }; + int32_t *fd_list = (int32_t *) &irq_set.data; + struct epoll_event event = { .events = EPOLLIN }; + + /* Create interrupt vectors with their respective eventfds. */ + dev->irq.vectors = (vfio_irq_t *) malloc(sizeof(vfio_irq_t) * dev->irq.vector_count); + for (int i = 0; i < dev->irq.vector_count; i++) { + dev->irq.vectors[i].dev = dev; + dev->irq.vectors[i].type = type; + dev->irq.vectors[i].vector = i; + fd_list[i] = dev->irq.vectors[i].fd = eventfd(0, 0); + if (fd_list[i] < 0) + pclog("VFIO %s: IRQ eventfd %d failed (%d)\n", dev->name, i, errno); + else { + /* Add eventfd to epoll. */ + event.data.ptr = &dev->irq.vectors[i]; + epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd_list[i], &event); + } + dev->irq.vectors[i].msix_offset = i << 4; /* pre-calculated value to save operations on MSI-X processing */ + } + + /* Enable interrupt type on VFIO. */ + if (ioctl(dev->fd, VFIO_DEVICE_SET_IRQS, &irq_set)) + pclog("VFIO %s: SET_IRQS(%d, %d) failed (%d)\n", dev->name, + type, dev->irq.vector_count, errno); + dev->irq.type = type; +} + +static void +vfio_region_init(vfio_device_t *dev, struct vfio_region_info *reg, vfio_region_t *region) +{ + /* Set region structure information. */ + region->fd = dev->fd; + region->offset = reg->offset; + if (reg->index == VFIO_PCI_VGA_REGION_INDEX) { + region->bar_id = 0xfe; + if (region == &dev->vga_io_lo) { + region->offset += 0x3b0; + region->size = 12; + region->type = 0x01; + } else if (region == &dev->vga_io_hi) { + region->offset += 0x3c0; + region->size = 32; + region->type = 0x01; + } else { + region->offset += 0xa0000; + region->size = 131072; + region->type = 0x00; + } + } else { + region->size = reg->size; + region->type = 0xff; + } + region->read = !!(reg->flags & VFIO_REGION_INFO_FLAG_READ); + region->write = !!(reg->flags & VFIO_REGION_INFO_FLAG_WRITE); + region->dev = dev; + + /* Use special memory mapping for expansion ROMs. */ + if (reg->index == VFIO_PCI_ROM_REGION_INDEX) { + /* Use MMIO only. */ + region->fd = -1; + + /* Open ROM file if one was given. */ + FILE *fp = NULL; + if (dev->rom_fn) { + pclog("VFIO %s: Loading ROM from file: %s\n", dev->name, dev->rom_fn); + fp = fopen(dev->rom_fn, "rb"); + if (fp) { + /* Determine region size if the device has no ROM region. */ + if (!region->size) { + fseek(fp, 0, SEEK_END); + region->size = ceilpow2(ftell(fp)); + if (region->size < 2048) /* minimum size for an expansion ROM */ + region->size = 2048; + fseek(fp, 0, SEEK_SET); + } + } else { + /* Fall back to the device's ROM if it has one. */ + pclog("VFIO %s: Could not read ROM file, ", dev->name); + if (region->size) { + pclog("falling back to device ROM\n"); + } else { + /* Disable ROM. */ + pclog("not enabling ROM\n"); + region->read = region->write = 0; + goto end; + } + } + } + + /* Mark this as the expansion ROM region. */ + region->type = 0x00; + region->bar_id = 0xff; + + /* Allocate ROM shadow area. */ + region->mmap_base = region->mmap_precalc = plat_mmap(region->size, 0); + if (region->mmap_base == ((void *) -1)) { + pclog("VFIO %s: ROM mmap(%" PRIu64 ") failed\n", dev->name, region->size); + region->mmap_base = NULL; + goto end; + } + memset(region->mmap_base, 0xff, region->size); + + int i, j = 0; + if (fp) { + /* Read ROM from file. */ + while ((i = fread(region->mmap_precalc, 1, + region->size - j, + fp)) + != 0) { + region->mmap_precalc += i; + j += i; + } + fclose(fp); + } else { + /* Read ROM from device. */ + while ((i = pread(dev->fd, region->mmap_precalc, + region->size - j, + region->offset + j)) + != 0) { + region->mmap_precalc += i; + j += i; + } + } + + /* Perform a few sanity checks on the ROM, starting with the signature. */ + j = 0; + if (*((uint16_t *) ®ion->mmap_base[0x00]) == 0xaa55) { + /* Check ROM length. */ + uint32_t rom_len = region->mmap_base[0x02] << 9; /* 512-byte blocks */ + if (rom_len > region->size) { + pclog("VFIO %s: Warning: ROM length (%d bytes) is larger than ROM region (%" PRIu64 " bytes)\n", + dev->name, rom_len, region->size); + j = 1; + } + + /* Check PCI pointer. */ + uint16_t pci_ptr = *((uint16_t *) ®ion->mmap_base[0x18]); + if (pci_ptr && (pci_ptr != 0xffff)) { + /* Check PCI pointer bounds. */ + if (pci_ptr <= (region->size - 0x12)) { + /* Check PCI header ROM length only if <= 130048 bytes, as the + ROM length is 8 bits in the main header and 16 bits in here. */ + uint32_t pci_len = *((uint16_t *) ®ion->mmap_base[pci_ptr + 0x18]) << 9; /* 512-byte blocks */ + if ((pci_len <= (254 << 9)) && (pci_len != rom_len)) { + pclog("VFIO %s: Warning: ROM length in main header (%d bytes) is " + "different from length in PCI header (%d bytes)\n", + dev->name, rom_len, pci_len); + j = 1; + } + } else { + pclog("VFIO %s: Warning: ROM has invalid PCI header pointer: %04X\n", + dev->name, pci_ptr); + j = 1; + } + } else { + pclog("VFIO %s: Warning: ROM has no PCI header pointer\n", + dev->name); + j = 1; + } + + /* Compare checksum. */ + uint8_t checksum = 0; + if (rom_len > region->size) /* don't go out of bounds */ + rom_len = region->size; + rom_len -= 1; + for (i = 0; i < rom_len; i++) + checksum -= region->mmap_base[i]; + if (checksum != region->mmap_base[i]) { + pclog("VFIO %s: Warning: ROM has bad checksum; expected %02X, got %02X\n", + dev->name, checksum, region->mmap_base[i]); + j = 1; + } + } else { + pclog("VFIO %s: Warning: ROM has no 55 AA signature\n", dev->name); + j = 1; + } + + /* Add a helpful reminder if a sanity check warning was printed + and no ROM file was specified in this device's configuration. */ + if (j && !dev->rom_fn) + pclog("VFIO %s: A custom ROM can be loaded with the _rom_fn directive.\n", dev->name); + } else { + /* Attempt to mmap the region. */ + region->mmap_base = mmap(NULL, region->size, + (region->read ? PROT_READ : 0) | (region->write ? PROT_WRITE : 0), + MAP_SHARED, region->fd, region->offset); + if (region->mmap_base == ((void *) -1)) /* mmap failed */ + region->mmap_base = NULL; + } + region->mmap_precalc = region->mmap_base; + +end: + vfio_log("VFIO %s: Region: %s (offset %lX) (%d bytes) ", dev->name, + region->name, region->offset, region->size); + + /* Create memory mapping for if we need it. */ + if (region->mmap_base) { /* mmap available */ + vfio_log("(MM)"); + mem_mapping_add(®ion->mem_mapping, 0, 0, + region->read ? vfio_mem_readb_mm : NULL, + region->read ? vfio_mem_readw_mm : NULL, + region->read ? vfio_mem_readl_mm : NULL, + region->write ? vfio_mem_writeb_mm : NULL, + region->write ? vfio_mem_writew_mm : NULL, + region->write ? vfio_mem_writel_mm : NULL, + NULL, MEM_MAPPING_EXTERNAL, region->mmap_precalc); + } else if (region->fd >= 0) { /* mmap not available, but fd is */ + vfio_log("(FD)"); + mem_mapping_add(®ion->mem_mapping, 0, 0, + region->read ? vfio_mem_readb_fd : NULL, + region->read ? vfio_mem_readw_fd : NULL, + region->read ? vfio_mem_readl_fd : NULL, + region->write ? vfio_mem_writeb_fd : NULL, + region->write ? vfio_mem_writew_fd : NULL, + region->write ? vfio_mem_writel_fd : NULL, + NULL, MEM_MAPPING_EXTERNAL, region); + } else { + vfio_log("(not mapped)"); + } + + vfio_log(" (%c%c)\n", region->read ? 'R' : '-', region->write ? 'W' : '-'); +} + +static void +vfio_region_close(vfio_device_t *dev, vfio_region_t *region) +{ + /* Stop if this region was not initialized. */ + if (!region->size) + return; + + /* Unmap memory if mmap was available. */ + if (region->mmap_base) + plat_munmap(region->mmap_base, region->size); +} + +static vfio_group_t * +vfio_group_get(int id, uint8_t add) +{ + /* Look for an existing group. */ + vfio_group_t *group = first_group; + while (group) { + if (group->id == id) + return group; + else if (group->next) + group = group->next; + else + break; + } + + /* Don't add a group if told not to. */ + if (!add) + return NULL; + + /* Add group if no matches were found. */ + if (group) { + group->next = (vfio_group_t *) malloc(sizeof(vfio_group_t)); + group = group->next; + } else { + group = first_group = (vfio_group_t *) malloc(sizeof(vfio_group_t)); + } + memset(group, 0, sizeof(vfio_group_t)); + group->id = id; + + /* Open VFIO group. */ + char group_file[32]; + snprintf(group_file, sizeof(group_file), "/dev/vfio/%d", group->id); + group->fd = open(group_file, O_RDWR); + if (group->fd < 0) { + pclog("VFIO: Group %d not found\n", group->id); + goto end; + } + + /* Check if the group is viable. */ + struct vfio_group_status group_status = { .argsz = sizeof(group_status) }; + if (ioctl(group->fd, VFIO_GROUP_GET_STATUS, &group_status)) { + pclog("VFIO: Group %d GET_STATUS failed (%d)\n", group->id, errno); + goto close_fd; + } else if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE)) { + pclog("VFIO: Group %d not viable\n", group->id); + goto close_fd; + } + + /* Claim the group. */ + if (ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container_fd)) { + pclog("VFIO: Group %d SET_CONTAINER failed\n", group->id); + goto close_fd; + } + + goto end; + +close_fd: + close(group->fd); + group->fd = -1; +end: + return group; +} + +static void +vfio_dev_prereset(vfio_device_t *dev) +{ + vfio_log("VFIO %s: prereset()\n", dev->name); + + /* Disable interrupts. */ + vfio_irq_disable(dev); + + /* Extra steps for devices with power management capability. */ + if (dev->pm_cap) { + /* Make sure the device is in D0 state. */ + uint8_t pm_ctrl = vfio_config_readb(0, dev->pm_cap + 4, dev), + state = pm_ctrl & 0x03; + if (state) { + pm_ctrl &= ~0x03; + vfio_config_writeb(0, dev->pm_cap + 4, pm_ctrl, dev); + + pm_ctrl = vfio_config_readb(0, dev->pm_cap + 4, dev); + state = pm_ctrl & 0x03; + if (state) + vfio_log("VFIO %s: Device stuck in D%d state\n", dev->name, state); + } + + /* Enable PM reset if the device supports it. */ + dev->can_pm_reset = !(pm_ctrl & 0x08); + } + + /* Enable function-level reset if supported. */ + dev->can_flr_reset = (dev->pcie_cap && (vfio_config_readb(0, dev->pcie_cap + 7, dev) & 0x10)) || (dev->af_cap && (vfio_config_readb(0, dev->af_cap + 3, dev) & 0x02)); + + /* Disable bus master, BARs, expansion ROM and VGA regions; also enable INTx. */ + vfio_config_writew(0, 0x04, vfio_config_readw(0, 0x04, dev) & ~0x0407, dev); +} + +static void +vfio_dev_postreset(vfio_device_t *dev) +{ + vfio_log("VFIO %s: postreset()\n", dev->name); + + /* Enable INTx interrupts. MSI(-X) can be enabled by the OS later. */ + if (!closing) + vfio_irq_enable(dev, VFIO_PCI_INTX_IRQ_INDEX); + + /* Reset BARs, whatever this does. */ + uint32_t val = 0; + for (uint8_t i = 0x10; i < 0x28; i++) + (void) !pwrite(dev->config.fd, &val, sizeof(val), dev->config.offset + i); +} + +static int +vfio_dev_init(vfio_device_t *dev) +{ + vfio_log("VFIO %s: init()\n", dev->name); + + /* Grab device. */ + dev->fd = ioctl(current_group->fd, VFIO_GROUP_GET_DEVICE_FD, dev->name); + if (dev->fd < 0) { + vfio_log("VFIO %s: GET_DEVICE_FD failed (%d)\n", dev->name, errno); + goto end; + } + + /* Get device information. */ + struct vfio_device_info device_info = { .argsz = sizeof(device_info) }; + if (ioctl(dev->fd, VFIO_DEVICE_GET_INFO, &device_info)) { + pclog("VFIO %s: GET_INFO failed (%d), check for error in kernel log\n", dev->name, errno); + goto end; + } + + /* Check if any regions were returned. */ + if (!device_info.num_regions) { + pclog("VFIO %s: No regions returned, check for error in kernel log\n", dev->name); + goto end; + } + + /* Set main reset flag. */ + dev->can_reset = !!(device_info.flags & VFIO_DEVICE_FLAGS_RESET); + + /* Establish region names. */ + for (uint8_t i = 0; i < 6; i++) { + sprintf(dev->bars[i].name, "BAR #%d", dev->bars[i].bar_id = i); + dev->bars[i].type = 0xff; + } + strcpy(dev->rom.name, "Expansion ROM"); + strcpy(dev->config.name, "Configuration space"); + strcpy(dev->vga_io_lo.name, "VGA MDA"); + strcpy(dev->vga_io_hi.name, "VGA CGA/EGA"); + strcpy(dev->vga_mem.name, "VGA Framebuffer"); + + /* Initialize all regions. */ + struct vfio_region_info reg = { .argsz = sizeof(reg) }; + uint8_t cls; + for (int i = 0; i < device_info.num_regions; i++) { + /* Get region information. */ + reg.index = i; + ioctl(dev->fd, VFIO_DEVICE_GET_REGION_INFO, ®); + + /* Move on to the next region if this one is not valid. */ + if (!reg.size) + continue; + + /* Initialize region according to its type. */ + switch (reg.index) { + case VFIO_PCI_BAR0_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX: + vfio_region_init(dev, ®, &dev->bars[reg.index - VFIO_PCI_BAR0_REGION_INDEX]); + if (reg.size) + dev->bar_count++; + break; + + case VFIO_PCI_ROM_REGION_INDEX: + vfio_region_init(dev, ®, &dev->rom); + break; + + case VFIO_PCI_CONFIG_REGION_INDEX: + vfio_region_init(dev, ®, &dev->config); + break; + + case VFIO_PCI_VGA_REGION_INDEX: + /* Don't initialize VGA region if this is not a video card. */ + if ((dev->config.fd > 0) && (pread(dev->config.fd, &cls, sizeof(cls), dev->config.offset + 0x0b) == sizeof(cls)) && (cls != 0x03)) + break; + + vfio_region_init(dev, ®, &dev->vga_io_lo); /* I/O [3B0:3BB] */ + vfio_region_init(dev, ®, &dev->vga_io_hi); /* I/O [3C0:3DF] */ + vfio_region_init(dev, ®, &dev->vga_mem); /* memory [A0000:BFFFF] */ + + /* Inform that a PCI VGA video card is attached if no video card is emulated. */ + if (gfxcard == VID_NONE) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_default); + break; + + default: + vfio_log("VFIO %s: Unknown region %d (offset %lX) (%d bytes) (%c%c)\n", + dev->name, reg.index, reg.offset, reg.size, + (reg.flags & VFIO_REGION_INFO_FLAG_READ) ? 'R' : '-', + (reg.flags & VFIO_REGION_INFO_FLAG_WRITE) ? 'W' : '-'); + break; + } + } + + /* Make sure we have a valid device. */ + if (!dev->config.fd || !dev->config.read) { + pclog("VFIO %s: No configuration space region\n", dev->name); + goto end; + } + + /* Initialize ROM region if the device doesn't have one and we're loading a ROM from file. */ + if (dev->rom_fn && !dev->rom.fd) { + reg.index = VFIO_PCI_ROM_REGION_INDEX; + reg.offset = reg.size = 0; + reg.flags = VFIO_REGION_INFO_FLAG_READ; + vfio_region_init(dev, ®, &dev->rom); + } + + /* Go through PCI capability list if the device declares one. */ + dev->irq.msix.table_bar = dev->irq.msix.pba_bar = 0x07; + uint8_t cap_ptr; + uint8_t cap_id; + if ((pread(dev->config.fd, &cap_ptr, sizeof(cap_ptr), dev->config.offset + 0x06) == sizeof(cap_ptr)) && (cap_ptr & 0x10)) { + vfio_log("VFIO %s: Device capabilities:", dev->name); + + /* Read pointer to the first capability. */ + if (pread(dev->config.fd, &cap_ptr, sizeof(cap_ptr), dev->config.offset + 0x34) != sizeof(cap_ptr)) + cap_ptr = 0; + while (cap_ptr && (cap_ptr != 0xff)) { /* check 0xff just in case */ + /* Read capability ID, and store pointers to ones we care about. */ + if (pread(dev->config.fd, &cap_id, sizeof(cap_id), dev->config.offset + cap_ptr) != sizeof(cap_id)) + cap_id = 0; + switch (cap_id) { + case 0x01: + vfio_log(" PM"); + dev->pm_cap = cap_ptr; + break; + + case 0x05: + vfio_log(" MSI"); + if (dev->msi_cap) /* multiple copies not permitted by spec */ + break; + dev->msi_cap = cap_ptr; + + /* Read control register. */ + if (pread(dev->config.fd, &dev->irq.msi.ctl, sizeof(dev->irq.msi.ctl), + dev->config.offset + dev->msi_cap + 2) + != sizeof(dev->irq.msi.ctl)) + dev->irq.msi.ctl = 0; + + /* Set vector count. */ + dev->irq.msi.vector_count = (dev->irq.msi.ctl >> 1) & 0x07; + break; + + case 0x10: + vfio_log(" PCIe"); + dev->pcie_cap = cap_ptr; + break; + + case 0x11: + vfio_log(" MSI-X"); + if (dev->msix_cap) /* multiple copies not permitted by spec */ + break; + dev->msix_cap = cap_ptr; + + /* Read control register. */ + if (pread(dev->config.fd, &dev->irq.msix.ctl, sizeof(dev->irq.msix.ctl), + dev->config.offset + dev->msix_cap + 2) + != sizeof(dev->irq.msix.ctl)) + dev->irq.msix.ctl = 0; + + /* Set vector count. */ + dev->irq.msix.vector_count = (dev->irq.msix.ctl & 0x07ff) + 1; + + /* Read table and PBA BARs and offsets. */ + if (pread(dev->config.fd, &dev->irq.msix.table_offset, sizeof(dev->irq.msix.table_offset), + dev->config.offset + dev->msix_cap + 4) + != sizeof(dev->irq.msix.table_offset)) + dev->irq.msix.table_offset = 0x00000007; + dev->irq.msix.table_bar = dev->irq.msix.table_offset & 0x00000007; + dev->irq.msix.table_offset &= 0xfffffff8; + + if (pread(dev->config.fd, &dev->irq.msix.pba_offset, sizeof(dev->irq.msix.pba_offset), + dev->config.offset + dev->msix_cap + 8) + != sizeof(dev->irq.msix.pba_offset)) + dev->irq.msix.pba_offset = 0x00000007; + dev->irq.msix.pba_bar = dev->irq.msix.pba_offset & 0x00000007; + dev->irq.msix.pba_offset &= 0xfffffff8; + + /* Allocate table and PBA structures. */ + dev->irq.msix.table_size = dev->irq.msix.vector_count << 4; + dev->irq.msix.table = malloc(dev->irq.msix.table_size); + if (!dev->irq.msix.table) { + pclog("VFIO %s: MSI-X table malloc(%d) failed\n", dev->name, dev->irq.msix.table_size); + dev->irq.msix.table_size = dev->irq.msix.vector_count = 0; + } + + dev->irq.msix.pba_size = ((dev->irq.msix.vector_count - 1) >> 3) + 1; + dev->irq.msix.pba = malloc(dev->irq.msix.pba_size); + if (!dev->irq.msix.pba) { + pclog("VFIO %s: MSI-X PBA malloc(%d) failed\n", dev->name, dev->irq.msix.pba_size); + dev->irq.msix.pba_size = dev->irq.msix.vector_count = 0; + } + + /* Add table and PBA mappings. + Being added after region setup, they should override the main BAR mapping. */ + mem_mapping_add(&dev->irq.msix.table_mapping, 0, 0, + vfio_irq_msix_table_readb, + vfio_irq_msix_table_readw, + vfio_irq_msix_table_readl, + vfio_irq_msix_table_writeb, + vfio_irq_msix_table_writew, + vfio_irq_msix_table_writel, + NULL, MEM_MAPPING_EXTERNAL, dev); + + mem_mapping_add(&dev->irq.msix.pba_mapping, 0, 0, + vfio_irq_msix_pba_readb, + vfio_irq_msix_pba_readw, + vfio_irq_msix_pba_readl, + vfio_irq_msix_pba_writeb, + vfio_irq_msix_pba_writew, + vfio_irq_msix_pba_writel, + NULL, MEM_MAPPING_EXTERNAL, dev); + break; + + case 0x13: + vfio_log(" AF"); + dev->af_cap = cap_ptr; + break; + + default: + vfio_log(" [%02X]", cap_id); + break; + } + + /* Read pointer to the next capability. */ + if (pread(dev->config.fd, &cap_ptr, sizeof(cap_ptr), dev->config.offset + cap_ptr + 1) != sizeof(cap_ptr)) + cap_ptr = 0; + } + + vfio_log("\n"); + } + + /* Read INTx IRQ pin. */ + vfio_irq_intx_setpin(dev); + + /* Add PCI card while mapping the configuration space. */ + pci_add_card(PCI_ADD_NORMAL, vfio_config_readb, vfio_config_writeb, dev, &dev->slot); + + return 0; + +end: + if (dev->fd >= 0) + close(dev->fd); + return 1; +} + +static void +vfio_dev_close(vfio_device_t *dev) +{ + vfio_log("VFIO %s: close()\n", dev->name); + + /* Close all regions. */ + for (uint8_t i = 0; i < 6; i++) + vfio_region_close(dev, &dev->bars[i]); + vfio_region_close(dev, &dev->rom); + vfio_region_close(dev, &dev->config); + vfio_region_close(dev, &dev->vga_io_lo); + vfio_region_close(dev, &dev->vga_io_hi); + vfio_region_close(dev, &dev->vga_mem); + + /* Close device fd. */ + if (dev->fd >= 0) { + close(dev->fd); + dev->fd = -1; + } + + /* Clean up. */ + if (dev->irq.msix.table) + free(dev->irq.msix.table); + if (dev->irq.msix.pba) + free(dev->irq.msix.pba); + free(dev->name); +} + +void +vfio_unmap_dma(uint32_t offset, uint32_t size) +{ + struct vfio_iommu_type1_dma_unmap dma_unmap = { + .argsz = sizeof(dma_unmap), + .iova = offset, + .size = size + }; + + vfio_log("VFIO: unmap_dma(%08X, %d)\n", offset, size); + + /* Unmap DMA region. */ + if (!ioctl(container_fd, VFIO_IOMMU_UNMAP_DMA, &dma_unmap)) + return; + + vfio_log("VFIO: unmap_dma(%08X, %d) failed (%d)\n", offset, size, errno); +} + +void +vfio_map_dma(uint8_t *ptr, uint32_t offset, uint32_t size) +{ + struct vfio_iommu_type1_dma_map dma_map = { + .argsz = sizeof(dma_map), + .vaddr = (uint64_t) ptr, + .iova = offset, + .size = size, + .flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE + }; + + vfio_log("VFIO: map_dma(%08X, %d)\n", offset, size); + + /* Map DMA region. */ + if (!ioctl(container_fd, VFIO_IOMMU_MAP_DMA, &dma_map)) + return; + + /* QEMU says mapping should be retried in case of EBUSY. */ + if (errno == EBUSY) { + vfio_unmap_dma(offset, size); + if (!ioctl(container_fd, VFIO_IOMMU_MAP_DMA, &dma_map)) + return; + } + + pclog("VFIO: map_dma(%08X, %d) failed (%d)\n", offset, size, errno); +} + +static void +vfio_reset(void *priv) +{ + vfio_log("VFIO: reset()\n"); + + /* Pre-reset and figure out the reset type for all devices. */ + int size; + int count; + struct vfio_pci_hot_reset_info *hot_reset_info; + struct vfio_pci_dependent_device *devices; + char name[13]; + vfio_group_t *group = first_group; + vfio_device_t *dev; + while (group) { + dev = group->first_device; + while (dev) { + /* Pre-reset this device. */ + vfio_dev_prereset(dev); + + /* Clear hot reset capable flag for this device. */ + dev->can_hot_reset = 0; + + /* Get hot reset information for the first time to get the entry count. */ + size = sizeof(struct vfio_pci_hot_reset_info); + hot_reset_info = (struct vfio_pci_hot_reset_info *) malloc(size); + if (!hot_reset_info) { + vfio_log("VFIO %s: malloc(hot_reset_info) 1 failed\n", dev->name); + goto next1; + } + memset(hot_reset_info, 0, size); + hot_reset_info->argsz = size; + if (ioctl(dev->fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, hot_reset_info) && (errno != ENOSPC)) { + vfio_log("VFIO %s: GET_PCI_HOT_RESET_INFO 1 failed (%d)\n", dev->name, errno); + goto next1; + } + count = hot_reset_info->count; + free(hot_reset_info); + + /* Get hot reset information for the second time to get the actual entries. */ + size = sizeof(struct vfio_pci_hot_reset) + (sizeof(struct vfio_pci_dependent_device) * count); + hot_reset_info = (struct vfio_pci_hot_reset_info *) malloc(size); + if (!hot_reset_info) { + vfio_log("VFIO %s: malloc(hot_reset_info) 2 failed\n", dev->name); + goto next1; + } + memset(hot_reset_info, 0, size); + hot_reset_info->argsz = size; + if (ioctl(dev->fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, hot_reset_info)) { + vfio_log("VFIO %s: GET_PCI_HOT_RESET_INFO 2 failed (%d)\n", dev->name, errno); + goto next1; + } + devices = &hot_reset_info->devices[0]; + + /* Go through the dependent device entries. */ + for (int i = 0; i < count; i++) { + /* Build this dependent device's name. */ + snprintf(name, sizeof(name), "%04x:%02x:%02x.%1x", + devices[i].segment, devices[i].bus, + PCI_SLOT(devices[i].devfn), PCI_FUNC(devices[i].devfn)); + + /* Check if we own this device's group. */ + if (!vfio_group_get(devices[i].group_id, 0)) { + vfio_log("VFIO %s: Cannot hot reset; we don't own" + "group %d for dependent device %s\n", + dev->name, devices[i].group_id, name); + goto next1; + } + } + + /* Mark this device as hot reset capable. */ + dev->can_hot_reset = 1; + +next1: + if (hot_reset_info) + free(hot_reset_info); + dev = dev->next; + } + group = group->next; + } + + /* Count the number of groups we own. */ + count = 0; + group = first_group; + while (group) { + count++; + group = group->next; + } + + /* Allocate hot reset structure. */ + struct vfio_pci_hot_reset *hot_reset; + size = sizeof(struct vfio_pci_hot_reset) + (sizeof(int32_t) * count); + hot_reset = (struct vfio_pci_hot_reset *) calloc(1, size); + hot_reset->argsz = size; + int32_t *fds = &hot_reset->group_fds[0]; + + /* Add group fds. */ + group = first_group; + while (group) { + fds[hot_reset->count++] = group->fd; + group = group->next; + } + + /* Reset all devices. */ + group = first_group; + while (group) { + dev = group->first_device; + while (dev) { + /* Try function-level reset. + I don't really understand the !pm_reset check, but QEMU does it. */ + if (dev->can_reset && (!dev->can_pm_reset || dev->can_flr_reset)) { + if (ioctl(dev->fd, VFIO_DEVICE_RESET)) + vfio_log("VFIO %s: DEVICE_RESET 1 failed (%d)\n", dev->name, errno); + else { + vfio_log("VFIO %s: FLR reset successful\n", dev->name); + goto next2; + } + } + + /* Try hot reset. */ + if (dev->can_hot_reset) { + if (ioctl(dev->fd, VFIO_DEVICE_PCI_HOT_RESET, hot_reset)) + vfio_log("VFIO %s: PCI_HOT_RESET failed (%d)\n", dev->name, errno); + else { + vfio_log("VFIO %s: Hot reset successful\n", dev->name); + goto next2; + } + } + + /* Try PM reset. */ + if (dev->can_reset && dev->can_pm_reset) { + if (ioctl(dev->fd, VFIO_DEVICE_RESET)) + vfio_log("VFIO %s: DEVICE_RESET 2 failed (%d)\n", dev->name, errno); + else { + vfio_log("VFIO %s: PM reset successful\n", dev->name); + goto next2; + } + } + + /* Warn if no reset types were successful. */ + pclog("VFIO %s: Device was not reset!\n", dev->name); + +next2: + dev = dev->next; + } + group = group->next; + } + + /* Clean up. */ + free(hot_reset); + + /* Post-reset all devices. */ + group = first_group; + while (group) { + dev = group->first_device; + while (dev) { + vfio_dev_postreset(dev); + dev = dev->next; + } + group = group->next; + } +} + +void +vfio_init(void) +{ + vfio_log("VFIO: init()\n"); + + /* Stay quiet if VFIO is not configured. */ + char *category = "VFIO", + *devices = config_get_string(category, "devices", NULL); + if (!devices || !strlen(devices)) + return; + + /* Open VFIO container. */ + container_fd = open("/dev/vfio/vfio", O_RDWR); + if (container_fd < 0) { + pclog("VFIO: Container not found (is vfio-pci loaded?)\n"); + return; + } + + /* Check VFIO API version. */ + int api = ioctl(container_fd, VFIO_GET_API_VERSION); + if (api != VFIO_API_VERSION) { + pclog("VFIO: Unknown API version %d (expected %d)\n", api, VFIO_API_VERSION); + goto close_container; + } + + /* Check for Type1 IOMMU support. */ + if (!ioctl(container_fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU)) { + pclog("VFIO: Type1 IOMMU not supported\n"); + goto close_container; + } + + /* Parse device list. */ + char *strtok_save; + char *token = strtok_r(devices, " ", &strtok_save); + char *p; + char *dev_name; + char *sysfs_device; + char *config_key; + int i; + int domain_id; + int bus_id; + int dev_id; + int func_id; + vfio_device_t *dev = NULL; + vfio_device_t *prev_dev; + vfio_group_t *group; + while (token) { + /* Determine if the device was specified by location or sysfs path. */ + dev_name = NULL; + if (token[0] == '/') { + /* sysfs path: use basename as device name. */ + i = strlen(token); + dev_name = malloc(i + 1); + strncpy(dev_name, path_get_basename(token), i); + + /* Just append iommu_group to the path. */ + sysfs_device = malloc(i + 13); + snprintf(sysfs_device, i + 13, + "%s/iommu_group", token); + } else if (token[0]) { + /* Location: read domain/bus/device/function. */ + i = sscanf(token, "%x:%x:%x.%x", &domain_id, &bus_id, &dev_id, &func_id); + if (i < 3) { + domain_id = 0; + i = sscanf(token, "%x:%x.%x", &bus_id, &dev_id, &func_id); + if (i < 2) { + bus_id = 0; + i = sscanf(token, "%x.%x", &dev_id, &func_id); + if (i < 1) { + pclog("VFIO: Invalid device location: %s\n", token); + goto next; + } else if (i == 1) { + func_id = 0; + } + } else if (i == 2) { + func_id = 0; + } + } else if (i == 3) { + func_id = 0; + } + + /* Use dddd:bb:dd.f as device name. */ + dev_name = malloc(13); + snprintf(dev_name, 13, + "%04x:%02x:%02x.%1x", domain_id, bus_id, dev_id, func_id); + + /* Generate sysfs path. */ + sysfs_device = malloc(46); + snprintf(sysfs_device, 46, + "/sys/bus/pci/devices/%s/iommu_group", dev_name); + } else { + /* Skip blank token. */ + goto next; + } + + pclog("VFIO %s: IOMMU group ", dev_name); + + p = realpath(sysfs_device, NULL); + free(sysfs_device); + if (p) { + /* Parse group ID. */ + if (sscanf(path_get_basename(p), "%d", &i) != 1) { + pclog("path could not be parsed: %s\n", p); + free(p); + goto next; + } + + pclog("%d\n", i); + free(p); + } else { + /* No symlink found, move on to the next device. */ + pclog("not found (%d)\n", errno); + goto next; + } + + /* Get group by ID, and move on to the next device + if the group failed to initialize. (Not viable, etc.) */ + group = vfio_group_get(i, 1); + if (group->fd < 0) { + pclog("VFIO %s: Skipping because group failed to initialize\n", dev_name); + goto next; + } + + /* Allocate device structure. */ + prev_dev = group->current_device; + dev = group->current_device = (vfio_device_t *) calloc(1, sizeof(vfio_device_t)); + + /* Initialize device structure. */ + dev->name = dev_name; + dev_name = NULL; /* don't free it further down */ + dev->irq.type = VFIO_PCI_NUM_IRQS; + + /* Read device-specific settings. */ + i = strlen(token) + 8; + config_key = malloc(i); + snprintf(config_key, i, "%s_rom_fn", token); + dev->rom_fn = config_get_string(category, config_key, NULL); + free(config_key); + + /* Add to linked device list. */ + if (prev_dev) + prev_dev->next = dev; + else + group->first_device = dev; + +next: /* Clean up. */ + if (dev_name) + free(dev_name); + + /* Read next device name. */ + token = strtok_r(NULL, " ", &strtok_save); + } + + /* Stop if no devices were added. */ + if (!dev) + goto close_container; + + /* Set IOMMU type. */ + if (ioctl(container_fd, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU)) { + pclog("VFIO: SET_IOMMU failed (%d)\n", errno); + goto close_container; + } + + /* Map RAM to container for DMA. */ + vfio_map_dma(ram, 0, 1024UL * MIN(mem_size, 1048576)); + if (ram2) + vfio_map_dma(ram2, 1024UL * 1048576, 1024UL * (mem_size - 1048576)); + + /* Initialize epoll. */ + epoll_fd = epoll_create1(0); + if (epoll_fd < 0) { + pclog("VFIO: epoll_create1 failed (%d)\n", errno); + goto close_container; + } + + /* Initialize IRQ thread wake eventfd. */ + irq_thread_wake_fd = eventfd(0, 0); + if (irq_thread_wake_fd <= 0) { + pclog("VFIO: eventfd failed (%d)\n", errno); + goto close_container; + } + struct epoll_event event = { .events = EPOLLIN }; + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, irq_thread_wake_fd, &event) < 0) { + pclog("VFIO: EPOLL_CTL_ADD failed (%d)\n", errno); + goto close_container; + } + + /* Initialize and start IRQ thread. */ + irq_event = thread_create_event(); + irq_thread_resume = thread_create_event(); + thread_set_event(irq_thread_resume); + irq_thread = thread_create(vfio_irq_thread, NULL); + + /* Start IRQ timer. */ + timer_add(&irq_timer, vfio_irq_timer, NULL, 0); + vfio_irq_timer(NULL); + + /* Initialize all devices. */ + current_group = first_group; + while (current_group) { + prev_dev = NULL; + dev = current_group->first_device; + while (dev) { + current_group->current_device = dev; + if (vfio_dev_init(dev)) { + pclog("VFIO %s: dev_init failed\n", dev->name); + + /* Deallocate this device if initialization failed. */ + if (prev_dev) + prev_dev->next = dev->next; + else + current_group->first_device = dev->next; + dev = dev->next; + free(current_group->current_device); + continue; + } + prev_dev = dev; + dev = dev->next; + } + current_group = current_group->next; + } + + /* Reset all devices. */ + vfio_log("VFIO: Performing initial reset\n"); + closing = 0; + + /* Add device_t to keep track of reset and close. */ + device_add(&vfio_device); + +close_container: + close(container_fd); + container_fd = -1; +} + +void +vfio_close(void *priv) +{ + vfio_log("VFIO: close()\n"); + + /* Reset all devices. */ + closing = 1; + vfio_reset(priv); + + /* Stop IRQ timer. */ + timer_on_auto(&irq_timer, 0.0); + + /* Stop IRQ thread by closing the epoll fd. */ + if (epoll_fd >= 0) { + close(epoll_fd); + epoll_fd = -1; + } + thread_set_event(irq_thread_resume); + + /* Close all groups. */ + while (first_group) { + current_group = first_group; + + /* Close all devices. */ + while (current_group->first_device) { + current_group->current_device = current_group->first_device; + + /* Close device. */ + vfio_dev_close(current_group->current_device); + + /* Deallocate device. */ + current_group->first_device = current_group->current_device->next; + free(current_group->current_device); + } + + /* Close group fd. */ + if (current_group->fd >= 0) + close(current_group->fd); + + /* Deallocate group. */ + first_group = current_group->next; + free(current_group); + } + + /* Close container. */ + if (container_fd >= 0) { + close(container_fd); + container_fd = -1; + } +} + +static void +vfio_speed_changed(void *priv) +{ + /* Set operation timings. */ + timing_readb = (int) (pci_timing * timing_default.read_b); + timing_readw = (int) (pci_timing * timing_default.read_w); + timing_readl = (int) (pci_timing * timing_default.read_l); + timing_writeb = (int) (pci_timing * timing_default.write_b); + timing_writew = (int) (pci_timing * timing_default.write_w); + timing_writel = (int) (pci_timing * timing_default.write_l); +} + +static const device_t vfio_device = { + .name = "VFIO PCI Passthrough", + .internal_name = "vfio", + .flags = DEVICE_PCI, + .local = 0, + .init = NULL, + .close = vfio_close, + .reset = vfio_reset, + .available = NULL, + .speed_changed = vfio_speed_changed, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/device/zenith_scratchpad.c b/src/device/zenith_scratchpad.c index 0db40c3f0..f71a9aada 100644 --- a/src/device/zenith_scratchpad.c +++ b/src/device/zenith_scratchpad.c @@ -9,8 +9,6 @@ * Emulation of various Zenith PC compatible machines. * Currently only the Zenith Data Systems Supersport is emulated. * - * - * * Authors: Tux, * Miran Grca, * TheCollector1995, diff --git a/src/discord.c b/src/discord.c index 18faee696..091d4c95f 100644 --- a/src/discord.c +++ b/src/discord.c @@ -8,8 +8,6 @@ * * Discord integration module. * - * - * * Authors: David Hrdlička, * * Copyright 2019 David Hrdlička. diff --git a/src/disk/hdc.c b/src/disk/hdc.c index 1e0d3f2bb..eb6c3a1b3 100644 --- a/src/disk/hdc.c +++ b/src/disk/hdc.c @@ -8,8 +8,6 @@ * * Common code to handle all sorts of disk controllers. * - * - * * Authors: Miran Grca, * Fred N. van Kempen, * diff --git a/src/disk/hdc_esdi_at.c b/src/disk/hdc_esdi_at.c index 64d292250..4838c23d3 100644 --- a/src/disk/hdc_esdi_at.c +++ b/src/disk/hdc_esdi_at.c @@ -8,8 +8,6 @@ * * Driver for the ESDI controller (WD1007-vse1) for PC/AT. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, diff --git a/src/disk/hdc_esdi_mca.c b/src/disk/hdc_esdi_mca.c index e59ae981d..78a2f3183 100644 --- a/src/disk/hdc_esdi_mca.c +++ b/src/disk/hdc_esdi_mca.c @@ -52,15 +52,12 @@ * however, are auto-configured by the system software as * shown above. * - * - * * Authors: Sarah Walker, * Fred N. van Kempen, * * Copyright 2008-2018 Sarah Walker. * Copyright 2017-2018 Fred N. van Kempen. */ - #include #include #include diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index e8c9fb05e..e9ee7083f 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -9,8 +9,6 @@ * Implementation of the IDE emulation for hard disks and ATAPI * CD-ROM devices. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/disk/hdc_ide_ali5213.c b/src/disk/hdc_ide_ali5213.c index 67f959e1a..ff837cbc6 100644 --- a/src/disk/hdc_ide_ali5213.c +++ b/src/disk/hdc_ide_ali5213.c @@ -8,8 +8,6 @@ * * Implementation of the ALi M1489 chipset. * - * - * * Authors: Tiseno100, * Miran Grca, * diff --git a/src/disk/hdc_ide_sff8038i.c b/src/disk/hdc_ide_sff8038i.c index 50deac38a..15dd4c515 100644 --- a/src/disk/hdc_ide_sff8038i.c +++ b/src/disk/hdc_ide_sff8038i.c @@ -10,8 +10,6 @@ * word 0 - base address * word 1 - bits 1-15 = byte count, bit 31 = end of transfer * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/disk/hdc_st506_at.c b/src/disk/hdc_st506_at.c index ed7b29d1f..5e50c44f0 100644 --- a/src/disk/hdc_st506_at.c +++ b/src/disk/hdc_st506_at.c @@ -12,8 +12,6 @@ * based design. Most cards were WD1003-WA2 or -WAH, where the * -WA2 cards had a floppy controller as well (to save space.) * - * - * * Authors: Sarah Walker, * Fred N. van Kempen, * diff --git a/src/disk/hdc_st506_xt.c b/src/disk/hdc_st506_xt.c index a7313ca63..de2536d83 100644 --- a/src/disk/hdc_st506_xt.c +++ b/src/disk/hdc_st506_xt.c @@ -41,8 +41,6 @@ * Since all controllers (including the ones made by DTC) use * (mostly) the same API, we keep them all in this module. * - * - * * Authors: Fred N. van Kempen, * Sarah Walker, * diff --git a/src/disk/hdc_xta_ps1.c b/src/disk/hdc_xta_ps1.c index ea71c918b..4a4273333 100644 --- a/src/disk/hdc_xta_ps1.c +++ b/src/disk/hdc_xta_ps1.c @@ -41,8 +41,6 @@ * Type table with the main code, so the user can only select * items from that list... * - * - * * Authors: Fred N. van Kempen, * * Based on my earlier HD20 driver for the EuroPC. diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index 63067f579..de79bca1b 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -21,8 +21,6 @@ * already on their way out, the newer IDE standard based on the * PC/AT controller and 16b design became the IDE we now know. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, diff --git a/src/disk/hdd.c b/src/disk/hdd.c index e48af6b20..af4411ab0 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -8,8 +8,6 @@ * * Common code to handle all sorts of hard disk images. * - * - * * Authors: Miran Grca, * Fred N. van Kempen, * diff --git a/src/disk/hdd_image.c b/src/disk/hdd_image.c index 75c27f4d1..79de77965 100644 --- a/src/disk/hdd_image.c +++ b/src/disk/hdd_image.c @@ -8,8 +8,6 @@ * * Handling of hard disk image files. * - * - * * Authors: Miran Grca, * Fred N. van Kempen, * diff --git a/src/disk/hdd_table.c b/src/disk/hdd_table.c index 12a0040ef..e0ff57b3f 100644 --- a/src/disk/hdd_table.c +++ b/src/disk/hdd_table.c @@ -9,8 +9,6 @@ * Implementation of the IDE emulation for hard disks and ATAPI * CD-ROM devices. * - * - * * Authors: Miran Grca, * Fred N. van Kempen, * diff --git a/src/dma.c b/src/dma.c index 2265947b9..bfc294f2a 100644 --- a/src/dma.c +++ b/src/dma.c @@ -8,8 +8,6 @@ * * Implementation of the Intel DMA controllers. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, @@ -1008,7 +1006,7 @@ dma_page_read(uint16_t addr, UNUSED(void *priv)) if (((addr & 0xfffc) == 0x80) && (CS == 0xf000) && ((cpu_state.pc & 0xfffffff8) == 0x00007278) && - !strcmp(machine_get_internal_name(), "megapc")) switch (addr) { + (machines[machine].init == machine_at_wd76c10_init)) switch (addr) { /* The Amstrad MegaPC Quadtel BIOS times a sequence of: mov ax,di div bx diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 1d3ae1abb..bcf4a1299 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -9,8 +9,6 @@ * Implementation of the NEC uPD-765 and compatible floppy disk * controller. * - * - * * Authors: Sarah Walker, * Miran Grca, * Toni Riikonen, @@ -2424,10 +2422,10 @@ fdc_reset(void *priv) need to use a dual-RPM 5.25" drive - but hey, that finally gets those drives some usage as well. */ - fdc_update_drvrate(fdc, 0, !strcmp(machine_get_internal_name(), "if386sx")); - fdc_update_drvrate(fdc, 1, !strcmp(machine_get_internal_name(), "if386sx")); - fdc_update_drvrate(fdc, 2, !strcmp(machine_get_internal_name(), "if386sx")); - fdc_update_drvrate(fdc, 3, !strcmp(machine_get_internal_name(), "if386sx")); + fdc_update_drvrate(fdc, 0, (machines[machine].init == machine_at_if386sx_init)); + fdc_update_drvrate(fdc, 1, (machines[machine].init == machine_at_if386sx_init)); + fdc_update_drvrate(fdc, 2, (machines[machine].init == machine_at_if386sx_init)); + fdc_update_drvrate(fdc, 3, (machines[machine].init == machine_at_if386sx_init)); fdc_update_drv2en(fdc, 1); fdc_update_rates(fdc); diff --git a/src/floppy/fdc_compaticard.c b/src/floppy/fdc_compaticard.c index cc438ddf6..1c668b470 100644 --- a/src/floppy/fdc_compaticard.c +++ b/src/floppy/fdc_compaticard.c @@ -12,7 +12,6 @@ * * Copyright 2022-2025 Jasmine Iwanek. */ - #include #include #include diff --git a/src/floppy/fdc_magitronic.c b/src/floppy/fdc_magitronic.c index a1ee922da..29db35006 100644 --- a/src/floppy/fdc_magitronic.c +++ b/src/floppy/fdc_magitronic.c @@ -12,7 +12,6 @@ * * Copyright 2021 Tiseno100 */ - #include #include #include diff --git a/src/floppy/fdc_monster.c b/src/floppy/fdc_monster.c index 38ad9e2ed..0bac3d590 100644 --- a/src/floppy/fdc_monster.c +++ b/src/floppy/fdc_monster.c @@ -8,8 +8,6 @@ * * Emulation of Sergey Kiselev's Monster Floppy Disk Controller. * - * - * * Authors: Jasmine Iwanek, * Miran Grca, * diff --git a/src/floppy/fdd.c b/src/floppy/fdd.c index 928e4290a..a0bef7ac6 100644 --- a/src/floppy/fdd.c +++ b/src/floppy/fdd.c @@ -8,8 +8,6 @@ * * Implementation of the floppy drive emulation. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, diff --git a/src/floppy/fdd_86f.c b/src/floppy/fdd_86f.c index f210bf4fd..0c64c41e7 100644 --- a/src/floppy/fdd_86f.c +++ b/src/floppy/fdd_86f.c @@ -10,8 +10,6 @@ * data in the form of FM/MFM-encoded transitions) which also * forms the core of the emulator's floppy disk emulation. * - * - * * Authors: Miran Grca, * Fred N. van Kempen, * diff --git a/src/floppy/fdd_audio.c b/src/floppy/fdd_audio.c index ed378bda8..84fcee5a6 100644 --- a/src/floppy/fdd_audio.c +++ b/src/floppy/fdd_audio.c @@ -24,6 +24,8 @@ #include <86box/timer.h> #include <86box/fdd.h> #include <86box/fdd_audio.h> +#include <86box/mem.h> +#include <86box/rom.h> #include <86box/sound.h> #include <86box/plat.h> #include <86box/path.h> @@ -65,23 +67,23 @@ typedef struct { /* 5.25" Teac FD-55GFR sample set */ static drive_audio_samples_t samples_teac = { .spindlemotor_start = { - .filename = "TeacFD-55GFR_5.25_1.2MB_motor_start_48000_16_1_PCM.wav", + .filename = "roms/floppy/samples/TeacFD-55GFR_5.25_1.2MB_motor_start_48000_16_1_PCM.wav", .buffer = NULL, .samples = 0, .volume = 3.0f }, .spindlemotor_loop = { - .filename = "TeacFD-55GFR_5.25_1.2MB_motor_loop_48000_16_1_PCM.wav", + .filename = "roms/floppy/samples/TeacFD-55GFR_5.25_1.2MB_motor_loop_48000_16_1_PCM.wav", .buffer = NULL, .samples = 0, .volume = 3.0f }, .spindlemotor_stop = { - .filename = "TeacFD-55GFR_5.25_1.2MB_motor_stop_48000_16_1_PCM.wav", + .filename = "roms/floppy/samples/TeacFD-55GFR_5.25_1.2MB_motor_stop_48000_16_1_PCM.wav", .buffer = NULL, .samples = 0, .volume = 3.0f }, .single_track_step = { - .filename = "TeacFD-55GFR_5.25_1.2MB_track_step_48000_16_1_PCM.wav", + .filename = "roms/floppy/samples/TeacFD-55GFR_5.25_1.2MB_track_step_48000_16_1_PCM.wav", .buffer = NULL, .samples = 0, .volume = 2.0f }, .multi_track_seek = { - .filename = "TeacFD-55GFR_5.25_1.2MB_seekupdown_80_tracks1100ms_48000_16_1_PCM.wav", + .filename = "roms/floppy/samples/TeacFD_55GFR_5.25_1.2MB_seekupdown_80_tracks1100ms_48000_16_1_PCM.wav", .buffer = NULL, .samples = 0, .volume = 2.0f } }; @@ -89,23 +91,23 @@ static drive_audio_samples_t samples_teac = { /* 3.5" drive audio samples (Mitsumi) */ static drive_audio_samples_t samples_35 = { .spindlemotor_start = { - .filename = "mitsumi_spindle_motor_start_48000_16_1_PCM.wav", + .filename = "roms/floppy/samples/mitsumi_spindle_motor_start_48000_16_1_PCM.wav", .buffer = NULL, .samples = 0, .volume = 0.2f }, .spindlemotor_loop = { - .filename = "mitsumi_spindle_motor_loop_48000_16_1_PCM.wav", + .filename = "roms/floppy/samples/mitsumi_spindle_motor_loop_48000_16_1_PCM.wav", .buffer = NULL, .samples = 0, .volume = 0.2f }, .spindlemotor_stop = { - .filename = "mitsumi_spindle_motor_stop_48000_16_1_PCM.wav", + .filename = "roms/floppy/samples/mitsumi_spindle_motor_stop_48000_16_1_PCM.wav", .buffer = NULL, .samples = 0, .volume = 0.2f }, .single_track_step = { - .filename = "mitsumi_track_step_48000_16_1_PCM.wav", + .filename = "roms/floppy/samples/mitsumi_track_step_48000_16_1_PCM.wav", .buffer = NULL, .samples = 0, .volume = 1.0f }, .multi_track_seek = { - .filename = "mitsumi_seek_80_tracks_495ms_48000_16_1_PCM.wav", + .filename = "roms/floppy/samples/mitsumi_seek_80_tracks_495ms_48000_16_1_PCM.wav", .buffer = NULL, .samples = 0, .volume = 1.0f } }; @@ -113,23 +115,23 @@ static drive_audio_samples_t samples_35 = { /* 5.25" drive audio samples (Panasonic) */ static drive_audio_samples_t samples_525 = { .spindlemotor_start = { - .filename = "Panasonic_JU-475-5_5.25_1.2MB_motor_start_48000_16_1_PCM.wav", + .filename = "roms/floppy/samples/Panasonic_JU-475-5_5.25_1.2MB_motor_start_48000_16_1_PCM.wav", .buffer = NULL, .samples = 0, .volume = 1.0f }, .spindlemotor_loop = { - .filename = "Panasonic_JU-475-5_5.25_1.2MB_motor_loop_48000_16_1_PCM.wav", + .filename = "roms/floppy/samples/Panasonic_JU-475-5_5.25_1.2MB_motor_loop_48000_16_1_PCM.wav", .buffer = NULL, .samples = 0, .volume = 1.0f }, .spindlemotor_stop = { - .filename = "Panasonic_JU-475-5_5.25_1.2MB_motor_stop_48000_16_1_PCM.wav", + .filename = "roms/floppy/samples/Panasonic_JU-475-5_5.25_1.2MB_motor_stop_48000_16_1_PCM.wav", .buffer = NULL, .samples = 0, .volume = 1.0f }, .single_track_step = { - .filename = "Panasonic_JU-475-5_5.25_1.2MB_track_step_48000_16_1_PCM.wav", + .filename = "roms/floppy/samples/Panasonic_JU-475-5_5.25_1.2MB_track_step_48000_16_1_PCM.wav", .buffer = NULL, .samples = 0, .volume = 2.0f }, .multi_track_seek = { - .filename = "Panasonic_JU-475-5_5.25_1.2MB_seekup_40_tracks_285ms_5ms_per_track_48000_16_1_PCM.wav", + .filename = "roms/floppy/samples/Panasonic_JU-475-5_5.25_1.2MB_seekup_40_tracks_285ms_5ms_per_track_48000_16_1_PCM.wav", .buffer = NULL, .samples = 0, .volume = 2.0f } }; @@ -176,17 +178,17 @@ load_wav(const char *filename, int *sample_count) FILE *f = NULL; char full_path[2048]; - if (!filename || strlen(filename) == 0) { + if ((filename == NULL) || (strlen(filename) == 0)) return NULL; } - if (strstr(filename, "..") != NULL || strchr(filename, '/') != NULL || strchr(filename, '\\') != NULL) { + if (strstr(filename, "..") != NULL) return NULL; } - for (const char *p = filename; *p; p++) { - if (!isalnum(*p) && *p != '.' && *p != '_' && *p != '-') { - return NULL; + f = rom_fopen(filename, "rb"); + if (f == NULL) + return NULL; } } @@ -515,11 +517,12 @@ fdd_audio_callback(int16_t *buffer, int length) if (!any_audio_active) return; - float *float_buffer = (float *) buffer; - int samples_in_buffer = length / 2; + float *float_buffer = (float *) buffer; + int16_t *int16_buffer = (int16_t *) buffer; + int samples_in_buffer = length / 2; /* Process audio for all drives */ - for (int drive = 0; drive < FDD_NUM; drive++) { + if (sound_is_float) for (int drive = 0; drive < FDD_NUM; drive++) { drive_audio_samples_t *samples = get_drive_samples(drive); if (!samples) continue; @@ -534,8 +537,8 @@ fdd_audio_callback(int16_t *buffer, int length) case MOTOR_STATE_STARTING: if (samples->spindlemotor_start.buffer && spindlemotor_pos[drive] < samples->spindlemotor_start.samples) { /* Play start sound with volume control */ - left_sample = (float) samples->spindlemotor_start.buffer[spindlemotor_pos[drive] * 2] / 32768.0f * samples->spindlemotor_start.volume; - right_sample = (float) samples->spindlemotor_start.buffer[spindlemotor_pos[drive] * 2 + 1] / 32768.0f * samples->spindlemotor_start.volume; + left_sample = (float) samples->spindlemotor_start.buffer[spindlemotor_pos[drive] * 2] / 131072.0f * samples->spindlemotor_start.volume; + right_sample = (float) samples->spindlemotor_start.buffer[spindlemotor_pos[drive] * 2 + 1] / 131072.0f * samples->spindlemotor_start.volume; spindlemotor_pos[drive]++; } else { /* Start sound finished, transition to loop */ @@ -547,8 +550,8 @@ fdd_audio_callback(int16_t *buffer, int length) case MOTOR_STATE_RUNNING: if (samples->spindlemotor_loop.buffer && samples->spindlemotor_loop.samples > 0) { /* Play loop sound with volume control */ - left_sample = (float) samples->spindlemotor_loop.buffer[spindlemotor_pos[drive] * 2] / 32768.0f * samples->spindlemotor_loop.volume; - right_sample = (float) samples->spindlemotor_loop.buffer[spindlemotor_pos[drive] * 2 + 1] / 32768.0f * samples->spindlemotor_loop.volume; + left_sample = (float) samples->spindlemotor_loop.buffer[spindlemotor_pos[drive] * 2] / 131072.0f * samples->spindlemotor_loop.volume; + right_sample = (float) samples->spindlemotor_loop.buffer[spindlemotor_pos[drive] * 2 + 1] / 131072.0f * samples->spindlemotor_loop.volume; spindlemotor_pos[drive]++; /* Loop back to beginning */ @@ -570,14 +573,14 @@ fdd_audio_callback(int16_t *buffer, int length) /* Get loop sample (continue from current position) with volume control */ if (samples->spindlemotor_loop.buffer && samples->spindlemotor_loop.samples > 0) { int loop_pos = spindlemotor_pos[drive] % samples->spindlemotor_loop.samples; - loop_left = (float) samples->spindlemotor_loop.buffer[loop_pos * 2] / 32768.0f * samples->spindlemotor_loop.volume; - loop_right = (float) samples->spindlemotor_loop.buffer[loop_pos * 2 + 1] / 32768.0f * samples->spindlemotor_loop.volume; + loop_left = (float) samples->spindlemotor_loop.buffer[loop_pos * 2] / 131072.0f * samples->spindlemotor_loop.volume; + loop_right = (float) samples->spindlemotor_loop.buffer[loop_pos * 2 + 1] / 131072.0f * samples->spindlemotor_loop.volume; } /* Get stop sample with volume control */ if (samples->spindlemotor_stop.buffer && spindlemotor_pos[drive] < samples->spindlemotor_stop.samples) { - stop_left = (float) samples->spindlemotor_stop.buffer[spindlemotor_pos[drive] * 2] / 32768.0f * samples->spindlemotor_stop.volume; - stop_right = (float) samples->spindlemotor_stop.buffer[spindlemotor_pos[drive] * 2 + 1] / 32768.0f * samples->spindlemotor_stop.volume; + stop_left = (float) samples->spindlemotor_stop.buffer[spindlemotor_pos[drive] * 2] / 131072.0f * samples->spindlemotor_stop.volume; + stop_right = (float) samples->spindlemotor_stop.buffer[spindlemotor_pos[drive] * 2 + 1] / 131072.0f * samples->spindlemotor_stop.volume; } /* Mix the sounds */ @@ -592,8 +595,8 @@ fdd_audio_callback(int16_t *buffer, int length) } else { /* Fade completed, play remaining stop sound with volume control */ if (samples->spindlemotor_stop.buffer && spindlemotor_pos[drive] < samples->spindlemotor_stop.samples) { - left_sample = (float) samples->spindlemotor_stop.buffer[spindlemotor_pos[drive] * 2] / 32768.0f * samples->spindlemotor_stop.volume; - right_sample = (float) samples->spindlemotor_stop.buffer[spindlemotor_pos[drive] * 2 + 1] / 32768.0f * samples->spindlemotor_stop.volume; + left_sample = (float) samples->spindlemotor_stop.buffer[spindlemotor_pos[drive] * 2] / 131072.0f * samples->spindlemotor_stop.volume; + right_sample = (float) samples->spindlemotor_stop.buffer[spindlemotor_pos[drive] * 2 + 1] / 131072.0f * samples->spindlemotor_stop.volume; spindlemotor_pos[drive]++; } else { /* Stop sound finished */ @@ -612,8 +615,8 @@ fdd_audio_callback(int16_t *buffer, int length) if (single_step_state[drive].active) { if (samples->single_track_step.buffer && single_step_state[drive].position < samples->single_track_step.samples) { /* Mix step sound with motor sound with volume control */ - float step_left = (float) samples->single_track_step.buffer[single_step_state[drive].position * 2] / 32768.0f * samples->single_track_step.volume; - float step_right = (float) samples->single_track_step.buffer[single_step_state[drive].position * 2 + 1] / 32768.0f * samples->single_track_step.volume; + float step_left = (float) samples->single_track_step.buffer[single_step_state[drive].position * 2] / 131072.0f * samples->single_track_step.volume; + float step_right = (float) samples->single_track_step.buffer[single_step_state[drive].position * 2 + 1] / 131072.0f * samples->single_track_step.volume; left_sample += step_left; right_sample += step_right; @@ -632,8 +635,8 @@ fdd_audio_callback(int16_t *buffer, int length) multi_seek_state[drive].position < multi_seek_state[drive].duration_samples && multi_seek_state[drive].position < samples->multi_track_seek.samples) { /* Mix seek sound with motor sound with volume control */ - float seek_left = (float) samples->multi_track_seek.buffer[multi_seek_state[drive].position * 2] / 32768.0f * samples->multi_track_seek.volume; - float seek_right = (float) samples->multi_track_seek.buffer[multi_seek_state[drive].position * 2 + 1] / 32768.0f * samples->multi_track_seek.volume; + float seek_left = (float) samples->multi_track_seek.buffer[multi_seek_state[drive].position * 2] / 131072.0f * samples->multi_track_seek.volume; + float seek_right = (float) samples->multi_track_seek.buffer[multi_seek_state[drive].position * 2 + 1] / 131072.0f * samples->multi_track_seek.volume; left_sample += seek_left; right_sample += seek_right; @@ -653,6 +656,140 @@ fdd_audio_callback(int16_t *buffer, int length) float_buffer[i * 2] += left_sample; float_buffer[i * 2 + 1] += right_sample; } + } else for (int drive = 0; drive < FDD_NUM; drive++) { + drive_audio_samples_t *samples = get_drive_samples(drive); + if (!samples) + continue; + + for (int i = 0; i < samples_in_buffer; i++) { + int16_t left_sample = 0.0f; + int16_t right_sample = 0.0f; + + /* Process motor audio */ + if (spindlemotor_state[drive] != MOTOR_STATE_STOPPED) { + switch (spindlemotor_state[drive]) { + case MOTOR_STATE_STARTING: + if (samples->spindlemotor_start.buffer && spindlemotor_pos[drive] < samples->spindlemotor_start.samples) { + /* Play start sound with volume control */ + left_sample = (int16_t) (float) samples->spindlemotor_start.buffer[spindlemotor_pos[drive] * 2] / 4.0f * samples->spindlemotor_start.volume; + right_sample = (int16_t) (float) samples->spindlemotor_start.buffer[spindlemotor_pos[drive] * 2 + 1] / 4.0f * samples->spindlemotor_start.volume; + spindlemotor_pos[drive]++; + } else { + /* Start sound finished, transition to loop */ + spindlemotor_state[drive] = MOTOR_STATE_RUNNING; + spindlemotor_pos[drive] = 0; + } + break; + + case MOTOR_STATE_RUNNING: + if (samples->spindlemotor_loop.buffer && samples->spindlemotor_loop.samples > 0) { + /* Play loop sound with volume control */ + left_sample = (int16_t) (float) samples->spindlemotor_loop.buffer[spindlemotor_pos[drive] * 2] / 4.0f * samples->spindlemotor_loop.volume; + right_sample = (int16_t) (float) samples->spindlemotor_loop.buffer[spindlemotor_pos[drive] * 2 + 1] / 4.0f * samples->spindlemotor_loop.volume; + spindlemotor_pos[drive]++; + + /* Loop back to beginning */ + if (spindlemotor_pos[drive] >= samples->spindlemotor_loop.samples) { + spindlemotor_pos[drive] = 0; + } + } + break; + + case MOTOR_STATE_STOPPING: + if (spindlemotor_fade_samples_remaining[drive] > 0) { + /* Mix fading loop sound with rising stop sound */ + float loop_volume = spindlemotor_fade_volume[drive]; + float stop_volume = 1.0f - loop_volume; + + int16_t loop_left = 0x0000, loop_right = 0x0000; + int16_t stop_left = 0x0000, stop_right = 0x0000; + + /* Get loop sample (continue from current position) with volume control */ + if (samples->spindlemotor_loop.buffer && samples->spindlemotor_loop.samples > 0) { + int loop_pos = spindlemotor_pos[drive] % samples->spindlemotor_loop.samples; + loop_left = (int16_t) (float) samples->spindlemotor_loop.buffer[loop_pos * 2] / 4.0f * samples->spindlemotor_loop.volume; + loop_right = (int16_t) (float) samples->spindlemotor_loop.buffer[loop_pos * 2 + 1] / 4.0f * samples->spindlemotor_loop.volume; + } + + /* Get stop sample with volume control */ + if (samples->spindlemotor_stop.buffer && spindlemotor_pos[drive] < samples->spindlemotor_stop.samples) { + stop_left = (int16_t) (float) samples->spindlemotor_stop.buffer[spindlemotor_pos[drive] * 2] / 4.0f * samples->spindlemotor_stop.volume; + stop_right = (int16_t) samples->spindlemotor_stop.buffer[spindlemotor_pos[drive] * 2 + 1] / 4.0f * samples->spindlemotor_stop.volume; + } + + /* Mix the sounds */ + left_sample = loop_left * loop_volume + stop_left * stop_volume; + right_sample = loop_right * loop_volume + stop_right * stop_volume; + + spindlemotor_pos[drive]++; + spindlemotor_fade_samples_remaining[drive]--; + + /* Update fade volume */ + spindlemotor_fade_volume[drive] = (int16_t) (float) spindlemotor_fade_samples_remaining[drive] / FADE_SAMPLES; + } else { + /* Fade completed, play remaining stop sound with volume control */ + if (samples->spindlemotor_stop.buffer && spindlemotor_pos[drive] < samples->spindlemotor_stop.samples) { + left_sample = (int16_t) (float) samples->spindlemotor_stop.buffer[spindlemotor_pos[drive] * 2] / 4.0f * samples->spindlemotor_stop.volume; + right_sample = (int16_t) (float) samples->spindlemotor_stop.buffer[spindlemotor_pos[drive] * 2 + 1] / 4.0f * samples->spindlemotor_stop.volume; + spindlemotor_pos[drive]++; + } else { + /* Stop sound finished */ + spindlemotor_state[drive] = MOTOR_STATE_STOPPED; + /* Note: Timer disabling is handled by fdd.c, not here */ + } + } + break; + + default: + break; + } + } + + /* Process single step audio */ + if (single_step_state[drive].active) { + if (samples->single_track_step.buffer && single_step_state[drive].position < samples->single_track_step.samples) { + /* Mix step sound with motor sound with volume control */ + int16_t step_left = (int16_t) (float) samples->single_track_step.buffer[single_step_state[drive].position * 2] / 4.0f * samples->single_track_step.volume; + int16_t step_right = (int16_t) (float) samples->single_track_step.buffer[single_step_state[drive].position * 2 + 1] / 4.0f * samples->single_track_step.volume; + + left_sample += step_left; + right_sample += step_right; + + single_step_state[drive].position++; + } else { + /* Step sound finished */ + single_step_state[drive].active = 0; + single_step_state[drive].position = 0; + } + } + + /* Process multi-track seek audio */ + if (multi_seek_state[drive].active) { + if (samples->multi_track_seek.buffer && + multi_seek_state[drive].position < multi_seek_state[drive].duration_samples && + multi_seek_state[drive].position < samples->multi_track_seek.samples) { + /* Mix seek sound with motor sound with volume control */ + int16_t seek_left = (int16_t) (float) samples->multi_track_seek.buffer[multi_seek_state[drive].position * 2] / 4.0f * samples->multi_track_seek.volume; + int16_t seek_right = (int16_t) (float) samples->multi_track_seek.buffer[multi_seek_state[drive].position * 2 + 1] / 4.0f * samples->multi_track_seek.volume; + + left_sample += seek_left; + right_sample += seek_right; + + multi_seek_state[drive].position++; + } else { + /* Seek sound finished */ + multi_seek_state[drive].active = 0; + multi_seek_state[drive].position = 0; + multi_seek_state[drive].duration_samples = 0; + multi_seek_state[drive].from_track = -1; + multi_seek_state[drive].to_track = -1; + } + } + + /* Mix this drive's audio into the buffer */ + int16_buffer[i * 2] += left_sample; + int16_buffer[i * 2 + 1] += right_sample; + } } } #else diff --git a/src/floppy/fdd_common.c b/src/floppy/fdd_common.c index d0659d990..ee694fac0 100644 --- a/src/floppy/fdd_common.c +++ b/src/floppy/fdd_common.c @@ -8,8 +8,6 @@ * * Shared code for all the floppy modules. * - * - * * Authors: Fred N. van Kempen, * * Copyright 2017-2018 Fred N. van Kempen. diff --git a/src/floppy/fdd_fdi.c b/src/floppy/fdd_fdi.c index 97b6441a0..835a06a53 100644 --- a/src/floppy/fdd_fdi.c +++ b/src/floppy/fdd_fdi.c @@ -9,8 +9,6 @@ * Implementation of the FDI floppy stream image format * interface to the FDI2RAW module. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, diff --git a/src/floppy/fdd_imd.c b/src/floppy/fdd_imd.c index 7994530ed..314b42927 100644 --- a/src/floppy/fdd_imd.c +++ b/src/floppy/fdd_imd.c @@ -8,8 +8,6 @@ * * Implementation of the IMD floppy image format. * - * - * * Authors: Fred N. van Kempen, * Miran Grca, * diff --git a/src/floppy/fdd_img.c b/src/floppy/fdd_img.c index 30e0212cd..5cd736377 100644 --- a/src/floppy/fdd_img.c +++ b/src/floppy/fdd_img.c @@ -13,8 +13,6 @@ * re-merged with the other files. Much of it is generic to * all formats. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, diff --git a/src/floppy/fdd_mfm.c b/src/floppy/fdd_mfm.c index 87da4e08b..68448bfab 100644 --- a/src/floppy/fdd_mfm.c +++ b/src/floppy/fdd_mfm.c @@ -8,8 +8,6 @@ * * Implementation of the HxC MFM image format. * - * - * * Authors: Miran Grca, * * Copyright 2018-2019 Miran Grca. diff --git a/src/floppy/fdd_pcjs.c b/src/floppy/fdd_pcjs.c index 6f69042b0..2193048c6 100644 --- a/src/floppy/fdd_pcjs.c +++ b/src/floppy/fdd_pcjs.c @@ -12,8 +12,6 @@ * * Copyright 2024 cold-brewed */ - - #include #include #include diff --git a/src/floppy/fdd_td0.c b/src/floppy/fdd_td0.c index f5882158b..f62e22c70 100644 --- a/src/floppy/fdd_td0.c +++ b/src/floppy/fdd_td0.c @@ -8,8 +8,6 @@ * * Implementation of the Teledisk floppy image format. * - * - * * Authors: Milodrag Milanovic, * Haruhiko OKUMURA, * Haruyasu YOSHIZAKI, diff --git a/src/floppy/fdi2raw.c b/src/floppy/fdi2raw.c index c6a41a52d..7c068e056 100644 --- a/src/floppy/fdi2raw.c +++ b/src/floppy/fdi2raw.c @@ -12,8 +12,6 @@ * addition of get_last_head and C++ callability by Thomas * Harte. * - * - * * Authors: Toni Wilen, * and Vincent Joguin, * Thomas Harte, diff --git a/src/gdbstub.c b/src/gdbstub.c index 2ae40d24c..cbbf0ede7 100644 --- a/src/gdbstub.c +++ b/src/gdbstub.c @@ -8,8 +8,6 @@ * * GDB stub server for remote debugging. * - * - * * Authors: RichardG, * * Copyright 2022 RichardG. @@ -535,8 +533,8 @@ gdbstub_client_write_reg(int index, uint8_t *buf) break; case GDB_REG_EFLAGS: - cpu_state.flags = *((uint16_t *) &buf[0]); - cpu_state.eflags = *((uint16_t *) &buf[2]); + cpu_state.flags = AS_U16(buf[0]); + cpu_state.eflags = AS_U16(buf[2]); break; case GDB_REG_CS ... GDB_REG_GS: @@ -564,8 +562,8 @@ gdbstub_client_write_reg(int index, uint8_t *buf) case GDB_REG_ST0 ... GDB_REG_ST7: width = 10; x87_conv_t conv = { - .eind = { .ll = *((uint64_t *) &buf[0]) }, - .begin = *((uint16_t *) &buf[8]) + .eind = { .ll = AS_U64(buf[0]) }, + .begin = AS_U16(buf[8]) }; cpu_state.ST[(cpu_state.TOP + (index - GDB_REG_ST0)) & 7] = x87_from80(&conv); break; @@ -671,8 +669,8 @@ gdbstub_client_read_reg(int index, uint8_t *buf) break; case GDB_REG_EFLAGS: - *((uint16_t *) &buf[0]) = cpu_state.flags; - *((uint16_t *) &buf[2]) = cpu_state.eflags; + AS_U16(buf[0]) = cpu_state.flags; + AS_U16(buf[2]) = cpu_state.eflags; break; case GDB_REG_CS ... GDB_REG_GS: @@ -697,8 +695,8 @@ gdbstub_client_read_reg(int index, uint8_t *buf) width = 10; x87_conv_t conv; x87_to80(cpu_state.ST[(cpu_state.TOP + (index - GDB_REG_ST0)) & 7], &conv); - *((uint64_t *) &buf[0]) = conv.eind.ll; - *((uint16_t *) &buf[8]) = conv.begin; + AS_U64(buf[0]) = conv.eind.ll; + AS_U16(buf[8]) = conv.begin; break; case GDB_REG_FCTRL ... GDB_REG_FSTAT: @@ -757,7 +755,7 @@ gdbstub_client_packet(gdbstub_client_t *client) #ifdef GDBSTUB_CHECK_CHECKSUM gdbstub_client_read_hex(client, &rcv_checksum, 1); #endif - *((uint16_t *) &client->packet[--client->packet_pos]) = 0; + AS_U16(client->packet[--client->packet_pos]) = 0; #ifdef GDBSTUB_CHECK_CHECKSUM for (i = 0; i < client->packet_pos; i++) checksum += client->packet[i]; diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index ebc86716f..6c924e031 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -79,6 +79,17 @@ #define BCD16(x) ((((x) / 1000) << 12) | (((x) / 100) << 8) | BCD8(x)) #define BCD32(x) ((((x) / 10000000) << 28) | (((x) / 1000000) << 24) | (((x) / 100000) << 20) | (((x) / 10000) << 16) | BCD16(x)) +#define AS_U8(x) (*((uint8_t *) &(x))) +#define AS_U16(x) (*((uint16_t *) &(x))) +#define AS_U32(x) (*((uint32_t *) &(x))) +#define AS_U64(x) (*((uint64_t *) &(x))) +#define AS_I8(x) (*((int8_t *) &(x))) +#define AS_I16(x) (*((int16_t *) &(x))) +#define AS_I32(x) (*((int32_t *) &(x))) +#define AS_I64(x) (*((int64_t *) &(x))) +#define AS_FLOAT(x) (*((float *) &(x))) +#define AS_DOUBLE(x) (*((double *) &(x))) + #if defined(__GNUC__) || defined(__clang__) # define UNLIKELY(x) __builtin_expect((x), 0) # define LIKELY(x) __builtin_expect((x), 1) diff --git a/src/include/86box/access_bus.h b/src/include/86box/access_bus.h index 333a1d4a5..84099a3db 100644 --- a/src/include/86box/access_bus.h +++ b/src/include/86box/access_bus.h @@ -8,8 +8,6 @@ * * Definitions for the ACPI emulation. * - * - * * Authors: Miran Grca, * * Copyright 2020-2025 Miran Grca. diff --git a/src/include/86box/isapnp.h b/src/include/86box/isapnp.h index 5e48b7c18..6f7eb1185 100644 --- a/src/include/86box/isapnp.h +++ b/src/include/86box/isapnp.h @@ -28,7 +28,8 @@ enum { ISAPNP_CARD_DISABLE = 0, ISAPNP_CARD_ENABLE = 1, ISAPNP_CARD_FORCE_CONFIG = 2, /* cheat code for UMC UM8669F */ - ISAPNP_CARD_NO_KEY = 3 /* cheat code for Crystal CS423x */ + ISAPNP_CARD_NO_KEY = 3, /* cheat code for Crystal CS423x */ + ISAPNP_CARD_FORCE_SLEEP = 4 /* cheat code for Yamaha YMF-71x */ }; typedef struct isapnp_device_config_t { diff --git a/src/include/86box/nv/vid_nv_rivatimer.h b/src/include/86box/nv/vid_nv_rivatimer.h index 59f6cfebf..659f683bd 100644 --- a/src/include/86box/nv/vid_nv_rivatimer.h +++ b/src/include/86box/nv/vid_nv_rivatimer.h @@ -8,7 +8,6 @@ * * Fast, high-frequency, guest CPU-independent timer for Riva emulation. * - * * Authors: Connor Hyde, I need a better email address ;^) * * Copyright 2024-2025 starfrost diff --git a/src/include/86box/plat.h b/src/include/86box/plat.h index 552b074f7..b76728047 100644 --- a/src/include/86box/plat.h +++ b/src/include/86box/plat.h @@ -150,6 +150,7 @@ extern void plat_get_temp_dir(char *outbuf, uint8_t len); extern void plat_get_vmm_dir(char *outbuf, size_t len); extern void plat_init_rom_paths(void); extern int plat_dir_check(char *path); +extern int plat_file_check(const char *path); extern int plat_dir_create(char *path); extern void *plat_mmap(size_t size, uint8_t executable); extern void plat_munmap(void *ptr, size_t size); diff --git a/src/include/86box/rom.h b/src/include/86box/rom.h index 331d78526..807649956 100644 --- a/src/include/86box/rom.h +++ b/src/include/86box/rom.h @@ -59,7 +59,7 @@ extern void rom_writel(uint32_t addr, uint32_t val, void *priv); extern void rom_get_full_path(char *dest, const char *fn); extern FILE *rom_fopen(const char *fn, char *mode); -extern int rom_getfile(char *fn, char *s, int size); +extern int rom_getfile(const char *fn, char *s, int size); extern int rom_present(const char *fn); extern int rom_load_linear_oddeven(const char *fn, uint32_t addr, int sz, diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index 3f468b7f0..5815d3f66 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -244,6 +244,9 @@ extern const device_t ncr_business_audio_device; /* Yamaha YMF-7xx */ extern const device_t ymf701_device; +extern const device_t ymf715_onboard_device; +extern const device_t ymf718_device; +extern const device_t ymf719_device; #ifdef USE_LIBSERIALPORT /* External Audio device OPL2Board (Host Connected hardware)*/ diff --git a/src/include/86box/vfio.h b/src/include/86box/vfio.h new file mode 100644 index 000000000..2166070a0 --- /dev/null +++ b/src/include/86box/vfio.h @@ -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 Virtual Function I/O PCI passthrough. + * + * Authors: RichardG, + * + * Copyright 2021-2025 RichardG. + */ +#if !defined(EMU_VFIO_H) && defined(USE_VFIO) +# define EMU_VFIO_H + +extern void vfio_init(void); + +#endif diff --git a/src/include/fdi2raw.h b/src/include/fdi2raw.h index b848b26f2..68e90ba9b 100644 --- a/src/include/fdi2raw.h +++ b/src/include/fdi2raw.h @@ -8,8 +8,6 @@ * * Definitions for the FDI floppy file format. * - * - * * Authors: Toni Wilen, * and Vincent Joguin, * Thomas Harte, diff --git a/src/io.c b/src/io.c index 45dd4cb3d..233dd6704 100644 --- a/src/io.c +++ b/src/io.c @@ -8,8 +8,6 @@ * * Implement I/O ports and their operations. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, diff --git a/src/ioapic.c b/src/ioapic.c index ea0811f91..4c28c2c64 100644 --- a/src/ioapic.c +++ b/src/ioapic.c @@ -9,8 +9,6 @@ * Skeleton I/O APIC implementation, currently housing the MPS * table patcher for machines that require it. * - * - * * Authors: RichardG, * * Copyright 2020 RichardG. diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c index 809a4a701..cded8e4f9 100644 --- a/src/machine/m_amstrad.c +++ b/src/machine/m_amstrad.c @@ -29,8 +29,6 @@ * All models: The internal mouse controller does not work correctly with * version 7.04 of the mouse driver. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, diff --git a/src/machine/m_at_386dx.c b/src/machine/m_at_386dx.c index 9cb7c5223..7fb045d58 100644 --- a/src/machine/m_at_386dx.c +++ b/src/machine/m_at_386dx.c @@ -68,9 +68,9 @@ static const device_config_t deskpro386_config[] = { .file_filter = "", .spinner = { 0 }, .bios = { - { .name = "September 1986", .internal_name = "deskpro386", .bios_type = BIOS_NORMAL, + { .name = "September 1986", .internal_name = "deskpro386_09_1986", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 65536, .files = { "roms/machines/deskpro386/1986-09-04-HI.json.bin", "" } }, - { .name = "May 1988", .internal_name = "deskpro386_05_1988", .bios_type = BIOS_NORMAL, + { .name = "May 1988", .internal_name = "deskpro386", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 65536, .files = { "roms/machines/deskpro386/1988-05-10.json.bin", "" } }, { .files_no = 0 } }, diff --git a/src/machine/m_at_386sx.c b/src/machine/m_at_386sx.c index 7e57c5902..0dc9142db 100644 --- a/src/machine/m_at_386sx.c +++ b/src/machine/m_at_386sx.c @@ -254,7 +254,7 @@ static const device_config_t c325ax_config[] = { }; const device_t c325ax_device = { - .name = "Chaintech 325AX", + .name = "Chaintech 3xxAX/AXB", .internal_name = "325ax_device", .flags = 0, .local = 0, diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index b80082d99..4c25799f6 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -359,9 +359,9 @@ static const device_config_t bx6_config[] = { .file_filter = "", .spinner = { 0 }, .bios = { - { .name = "1998/07/28 - BIOS EG", .internal_name = "bx6", .bios_type = BIOS_NORMAL, + { .name = "Award Modular BIOS v4.51PG - Revision EG", .internal_name = "bx6_eg", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/bx6/BX6_EG.BIN", "" } }, - { .name = "2000/03/10 - BIOS QS", .internal_name = "bx6_qs", .bios_type = BIOS_NORMAL, + { .name = "Award Modular BIOS v4.51PG - Revision QS", .internal_name = "bx6", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/bx6/BX6_QS.bin", "" } }, { .files_no = 0 } }, @@ -371,7 +371,7 @@ static const device_config_t bx6_config[] = { }; const device_t bx6_device = { - .name = "ABIT BX6", + .name = "ABIT AB-BX6", .internal_name = "bx6_device", .flags = 0, .local = 0, @@ -570,14 +570,14 @@ static const device_config_t ms6119_config[] = { .file_filter = "", .spinner = { 0 }, .bios = { - { .name = "Award Modular BIOS v4.51PG - Version 3.30b1 (LG IBM Multinet i x7G)", .internal_name = "lgibmx7g", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 262144, .files = { "roms/machines/ms6119/ms6119.331", "" } }, - { .name = "Award Modular BIOS v4.51PG - Version 2.12 (Viglen Vig69M)", .internal_name = "vig69m", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 262144, .files = { "roms/machines/ms6119/vig69m.212", "" } }, - { .name = "Award Modular BIOS v4.51PG - Version 2.10", .internal_name = "ms6119", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 262144, .files = { "roms/machines/ms6119/w6119ims.2a0", "" } }, - { .name = "AMIBIOS 071595 - Version 1.90 (Packard Bell Tacoma)", .internal_name = "tacoma", .bios_type = BIOS_NORMAL, + { .name = "AMIBIOS 6 (071595) - Revision 1.90 (Packard Bell Tacoma)", .internal_name = "tacoma", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 262144, .files = { "roms/machines/ms6119/A19P2190.ROM", "" } }, + { .name = "Award Modular BIOS v4.51PG - Revision 2.10", .internal_name = "ms6119", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 262144, .files = { "roms/machines/ms6119/w6119ims.2a0", "" } }, + { .name = "Award Modular BIOS v4.51PG - Revision 2.12 (Viglen Vig69M)", .internal_name = "vig69m", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 262144, .files = { "roms/machines/ms6119/vig69m.212", "" } }, + { .name = "Award Modular BIOS v4.51PG - Revision 3.30b1 (LG IBM Multinet i x7G)", .internal_name = "lgibmx7g", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 262144, .files = { "roms/machines/ms6119/ms6119.331", "" } }, { .files_no = 0 } }, }, diff --git a/src/machine/m_at_socket3.c b/src/machine/m_at_socket3.c index 2d6ea9730..8d460186c 100644 --- a/src/machine/m_at_socket3.c +++ b/src/machine/m_at_socket3.c @@ -178,11 +178,11 @@ static const device_config_t j403tg_config[] = { .file_filter = "", .spinner = { 0 }, .bios = { - { .name = "Award Modular BIOS v4.50G", .internal_name = "403tg", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 65536, .files = { "roms/machines/403tg/403TG.BIN", "" } }, - { .name = "AMI WinBIOS (121593)", .internal_name = "403tg_d", .bios_type = BIOS_NORMAL, + { .name = "AMI WinBIOS (121593)", .internal_name = "403tg", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 65536, .files = { "roms/machines/403tg/J403TGRevD.BIN", "" } }, - { .name = "MR BIOS V2.02", .internal_name = "403tg_d_mr", .bios_type = BIOS_NORMAL, + { .name = "Award Modular BIOS v4.50G", .internal_name = "403tg_award", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 65536, .files = { "roms/machines/403tg/403TG.BIN", "" } }, + { .name = "MR BIOS V2.02", .internal_name = "403tg_mr", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 65536, .files = { "roms/machines/403tg/MRBiosOPT895.bin", "" } }, { .files_no = 0 } }, diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index ee276566a..b3d504148 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -151,7 +151,7 @@ static const device_config_t cu430hx_config[] = { .file_filter = "", .spinner = { 0 }, .bios = { - { .name = "Intel AMIBIOS - Revision 1.00.03.DK08 (Toshiba Equium 5200D)", .internal_name = "equium5200", .bios_type = BIOS_NORMAL, + { .name = "Intel AMIBIOS - Revision 1.00.03.DK08 (Toshiba Equium 5xx0D)", .internal_name = "equium5200", .bios_type = BIOS_NORMAL, .files_no = 5, .local = 0, .size = 262144, .files = { "roms/machines/cu430hx/1003DK08.BIO", "roms/machines/cu430hx/1003DK08.BI1", "roms/machines/cu430hx/1003DK08.BI2", "roms/machines/cu430hx/1003DK08.BI3", "roms/machines/cu430hx/1003DK08.RCV", "" } }, @@ -270,7 +270,7 @@ static const device_config_t tc430hx_config[] = { .files_no = 5, .local = 0, .size = 262144, .files = { "roms/machines/tc430hx/1007DH0_.BIO", "roms/machines/tc430hx/1007DH0_.BI1", "roms/machines/tc430hx/1007DH0_.BI2", "roms/machines/tc430hx/1007DH0_.BI3", "roms/machines/tc430hx/1007DH0_.RCV", "" } }, - { .name = "Intel AMIBIOS - Revision 1.00.08.DH08 (Toshiba Infinia 7201)", .internal_name = "infinia7200", .bios_type = BIOS_NORMAL, + { .name = "Intel AMIBIOS - Revision 1.00.08.DH08 (Toshiba Infinia 7xx1)", .internal_name = "infinia7200", .bios_type = BIOS_NORMAL, .files_no = 5, .local = 0, .size = 262144, .files = { "roms/machines/tc430hx/1008DH08.BIO", "roms/machines/tc430hx/1008DH08.BI1", "roms/machines/tc430hx/1008DH08.BI2", "roms/machines/tc430hx/1008DH08.BI3", "roms/machines/tc430hx/1008DH08.RCV", "" } }, @@ -1365,6 +1365,9 @@ machine_at_an430tx_init(const machine_t *model) device_add(&intel_flash_bxt_ami_device); spd_register(SPD_TYPE_SDRAM, 0x3, 128); + if (sound_card_current[0] == SOUND_INTERNAL) + machine_snd = device_add(machine_get_snd_device(machine)); + return ret; } @@ -1806,9 +1809,9 @@ static const device_config_t m5ata_config[] = { .file_filter = "", .spinner = { 0 }, .bios = { - { .name = "Award Modular BIOS v4.51PG - Revision 12/23/97", .internal_name = "m5ata", .bios_type = BIOS_NORMAL, + { .name = "Award Modular BIOS v4.51PG - Revision 12/23/97", .internal_name = "m5ata_1223", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/m5ata/ATA1223.BIN", "" } }, - { .name = "Award Modular BIOS v4.51PG - Revision 05/27/98", .internal_name = "m5ata_0527b", .bios_type = BIOS_NORMAL, + { .name = "Award Modular BIOS v4.51PG - Revision 05/27/98", .internal_name = "m5ata", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/m5ata/ATA0527B.BIN", "" } }, { .files_no = 0 } }, diff --git a/src/machine/m_at_socket8.c b/src/machine/m_at_socket8.c index 3d5f4787e..11262ef4a 100644 --- a/src/machine/m_at_socket8.c +++ b/src/machine/m_at_socket8.c @@ -111,7 +111,7 @@ static const device_config_t ficpo6000_config[] = { .name = "bios", .description = "BIOS Version", .type = CONFIG_BIOS, - .default_string = "405F03C", + .default_string = "405F05C", .default_int = 0, .file_filter = "", .spinner = { 0 }, /*W1*/ diff --git a/src/machine/m_elt.c b/src/machine/m_elt.c index 2c807782c..17775d430 100644 --- a/src/machine/m_elt.c +++ b/src/machine/m_elt.c @@ -30,7 +30,6 @@ * Boston, MA 02111-1307 * USA. */ - #include #include #include diff --git a/src/machine/m_europc.c b/src/machine/m_europc.c index d85563241..c388e64e3 100644 --- a/src/machine/m_europc.c +++ b/src/machine/m_europc.c @@ -68,8 +68,6 @@ * * WARNING THIS IS A WORK-IN-PROGRESS MODULE. USE AT OWN RISK. * - * - * * Authors: Fred N. van Kempen, * * Inspired by the "jim.c" file originally present, but a diff --git a/src/machine/m_pcjr.c b/src/machine/m_pcjr.c index 9dba8795f..9d4df7528 100644 --- a/src/machine/m_pcjr.c +++ b/src/machine/m_pcjr.c @@ -8,8 +8,6 @@ * * Emulation of the IBM PCjr. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index c8973cbb1..534424609 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -22,8 +22,6 @@ * The reserved 384K is remapped to the top of extended memory. * If this is not done then you get an error on startup. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index 4a3d94ab3..d35a31451 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -8,8 +8,6 @@ * * Implementation of MCA-based PS/2 machines. * - * - * * Authors: Fred N. van Kempen, * Miran Grca, * Sarah Walker, diff --git a/src/machine/m_tandy.c b/src/machine/m_tandy.c index 899e819f7..9ac254e44 100644 --- a/src/machine/m_tandy.c +++ b/src/machine/m_tandy.c @@ -8,8 +8,6 @@ * * Emulation of Tandy models 1000, 1000HX and 1000SL2. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/machine/m_xt_t1000.c b/src/machine/m_xt_t1000.c index 080a03d19..13407c535 100644 --- a/src/machine/m_xt_t1000.c +++ b/src/machine/m_xt_t1000.c @@ -51,8 +51,6 @@ * NOTE: Still need to figure out a way to load/save ConfigSys and * HardRAM stuff. Needs to be linked in to the NVR code. * - * - * * Authors: Fred N. van Kempen, * Miran Grca, * John Elliott, diff --git a/src/machine/machine.c b/src/machine/machine.c index 50b0bb150..55bc141c0 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -8,8 +8,6 @@ * * Handling of the emulated machines. * - * - * * Authors: Miran Grca, * Fred N. van Kempen, * diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 3d241401d..cbc48db1d 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -4075,7 +4075,7 @@ const machine_t machines[] = { .ram = { .min = 512, .max = 1024, - .step = 512 + .step = 128 }, .nvrmask = 63, .jumpered_ecp_dma = 0, @@ -5244,6 +5244,50 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has a JetKey KBC without version, which is a clone of AMI '8'. */ + { + .name = "[ALi M1217] Chaintech 3xxAX/AXB", + .internal_name = "325ax", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_ALI_M1217, + .init = machine_at_325ax_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 1024, + .max = 16384, + .step = 1024 + }, + .nvrmask = 127, + .jumpered_ecp_dma = 0, + .default_jumpered_ecp_dma = -1, + .kbc_device = &kbc_at_device, + .kbc_params = KBC_VEN_AMI | 0x00003800, + .kbc_p1 = 0x000004f0, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = &c325ax_device, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* Has a VIA VT82C42N KBC. */ { .name = "[ALi M1217] Flytech A36", @@ -5288,50 +5332,6 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - /* Has a JetKey KBC without version, which is a clone of AMI '8'. */ - { - .name = "[ALi M1217] Chaintech 325AX", - .internal_name = "325ax", - .type = MACHINE_TYPE_386SX, - .chipset = MACHINE_CHIPSET_ALI_M1217, - .init = machine_at_325ax_init, - .p1_handler = machine_generic_p1_handler, - .gpio_handler = NULL, - .available_flag = MACHINE_AVAILABLE, - .gpio_acpi_handler = NULL, - .cpu = { - .package = CPU_PKG_386SX, - .block = CPU_BLOCK_NONE, - .min_bus = 0, - .max_bus = 0, - .min_voltage = 0, - .max_voltage = 0, - .min_multi = 0, - .max_multi = 0 - }, - .bus_flags = MACHINE_AT, - .flags = MACHINE_FLAGS_NONE, - .ram = { - .min = 1024, - .max = 16384, - .step = 1024 - }, - .nvrmask = 127, - .jumpered_ecp_dma = 0, - .default_jumpered_ecp_dma = -1, - .kbc_device = &kbc_at_device, - .kbc_params = KBC_VEN_AMI | 0x00003800, - .kbc_p1 = 0x000004f0, - .gpio = 0xffffffff, - .gpio_acpi = 0xffffffff, - .device = &c325ax_device, - .kbd_device = NULL, - .fdc_device = NULL, - .sio_device = NULL, - .vid_device = NULL, - .snd_device = NULL, - .net_device = NULL - }, /* Uses a NEC/Acer 90M002A. This is a strange one - it has command AF but it returns 0x00. */ { @@ -7385,7 +7385,7 @@ const machine_t machines[] = { /* Has AMIKey H KBC firmware, per the screenshot in "How computers & MS-DOS work". Also seen with an AMI 'F'. */ { - .name = "[SiS 401] Chaintech 433SC", + .name = "[SiS 401] Chaintech 4xxSX/SC", .internal_name = "sis401", .type = MACHINE_TYPE_486, .chipset = MACHINE_CHIPSET_SIS_401, @@ -7429,7 +7429,7 @@ const machine_t machines[] = { }, /* Seen with both AMIKey F and AMIKey-2 H KBC firmwares. */ { - .name = "[SiS 460] ABIT AV4", + .name = "[SiS 460] ABIT AB-AV4", .internal_name = "av4", .type = MACHINE_TYPE_486, .chipset = MACHINE_CHIPSET_SIS_460, @@ -10682,7 +10682,7 @@ const machine_t machines[] = { /* This has the UMC 88xx on-chip KBC. All the copies of the BIOS string I can find, end in in -H, so the UMC on-chip KBC likely emulates the AMI 'H' KBC firmware. */ { - .name = "[UMC 8881] PC Chips M919", + .name = "[UMC 8881] PCChips M919", .internal_name = "m919", .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_UMC_UM8881, @@ -13198,7 +13198,7 @@ const machine_t machines[] = { }, /* Has a VIA VT82C42N KBC. */ { - .name = "[i430FX] PC Partner MB500N", + .name = "[i430FX] PCPartner MB500N", .internal_name = "mb500n", .type = MACHINE_TYPE_SOCKET7_3V, .chipset = MACHINE_CHIPSET_INTEL_430FX, @@ -13828,7 +13828,7 @@ const machine_t machines[] = { }, /* Has the ALi M1543 southbridge with on-chip KBC. */ { - .name = "[ALi ALADDiN IV+] PC Chips M560", + .name = "[ALi ALADDiN IV+] PCChips M560", .internal_name = "m560", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_ALI_ALADDIN_IV_PLUS, @@ -14913,7 +14913,7 @@ const machine_t machines[] = { /* This has the AMIKey 'H' firmware, possibly AMIKey-2. Photos show it with a BestKey, so it likely clones the behavior of AMIKey 'H'. */ { - .name = "[i430VX] PC Partner MB520N", + .name = "[i430VX] PCPartner MB520N", .internal_name = "mb520n", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_INTEL_430VX, @@ -15352,7 +15352,7 @@ const machine_t machines[] = { .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI, - .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, /* Machine has internal video: ATI Mach64GT-B 3D Rage II */ + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_SOUND | MACHINE_GAMEPORT, /* Machine has internal video: ATI Mach64GT-B 3D Rage II */ .ram = { .min = 8192, .max = 262144, @@ -15371,13 +15371,13 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, - .snd_device = NULL, + .snd_device = &ymf715_onboard_device, .net_device = NULL }, /* The BIOS sends KBC command BB and expects it to output a byte, which is AMI KBC behavior. A picture shows a VIA VT82C42N KBC though, so it could be a case of that KBC with AMI firmware. */ { - .name = "[i430TX] PC Partner MB540N", + .name = "[i430TX] PCPartner MB540N", .internal_name = "mb540n", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_INTEL_430TX, @@ -15476,7 +15476,7 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_Cx6x86MX), .min_bus = 50000000, .max_bus = 75000000, .min_voltage = 2100, @@ -15918,7 +15918,7 @@ const machine_t machines[] = { /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA VT82C42N. */ { - .name = "[VIA VP3] PC Partner VIA809DS", + .name = "[VIA VP3] PCPartner VIA809DS", .internal_name = "via809ds", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_VIA_APOLLO_VP3, @@ -16007,51 +16007,6 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - /* Is the exact same as the Matsonic MS6260S. Has the ALi M1543C southbridge - with on-chip KBC. */ - { - .name = "[ALi ALADDiN V] PC Chips M579", - .internal_name = "m579", - .type = MACHINE_TYPE_SOCKETS7, - .chipset = MACHINE_CHIPSET_ALI_ALADDIN_V, - .init = machine_at_m579_init, - .p1_handler = machine_generic_p1_handler, - .gpio_handler = NULL, - .available_flag = MACHINE_AVAILABLE, - .gpio_acpi_handler = NULL, - .cpu = { - .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, - .min_bus = 66666667, - .max_bus = 100000000, - .min_voltage = 2000, - .max_voltage = 3520, - .min_multi = 1.5, - .max_multi = 5.5 - }, - .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, - .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, /* Machine has internal sound: C-Media CMI8330 */ - .ram = { - .min = 8192, - .max = 1572864, - .step = 8192 - }, - .nvrmask = 255, - .jumpered_ecp_dma = 0, - .default_jumpered_ecp_dma = -1, - .kbc_device = NULL, - .kbc_params = 0x00000000, - .kbc_p1 = 0x00000cf0, - .gpio = 0xffffffff, - .gpio_acpi = 0xffffffff, - .device = NULL, - .kbd_device = NULL, - .fdc_device = NULL, - .sio_device = NULL, - .vid_device = NULL, - .snd_device = NULL, - .net_device = NULL - }, /* M1534c kbc */ { .name = "[ALi ALADDiN V] Gateway Lucas", @@ -16184,6 +16139,51 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Is the exact same as the Matsonic MS6260S. Has the ALi M1543C southbridge + with on-chip KBC. */ + { + .name = "[ALi ALADDiN V] PCChips M579", + .internal_name = "m579", + .type = MACHINE_TYPE_SOCKETS7, + .chipset = MACHINE_CHIPSET_ALI_ALADDIN_V, + .init = machine_at_m579_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 100000000, + .min_voltage = 2000, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 5.5 + }, + .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, /* Machine has internal sound: C-Media CMI8330 */ + .ram = { + .min = 8192, + .max = 1572864, + .step = 8192 + }, + .nvrmask = 255, + .jumpered_ecp_dma = 0, + .default_jumpered_ecp_dma = -1, + .kbc_device = NULL, + .kbc_params = 0x00000000, + .kbc_p1 = 0x00000cf0, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* SiS 5591 */ /* Has the SiS 5591 chipset with on-chip KBC. */ @@ -16954,7 +16954,7 @@ const machine_t machines[] = { }, /* Has a VIA VT82C42N KBC. */ { - .name = "[i440FX] PC Partner MB600N", + .name = "[i440FX] PCPartner MB600N", .internal_name = "mb600n", .type = MACHINE_TYPE_SOCKET8, .chipset = MACHINE_CHIPSET_INTEL_440FX, @@ -17001,7 +17001,7 @@ const machine_t machines[] = { /* ALi ALADDiN-PRO II */ /* Has the ALi M1543C southbridge with on-chip KBC. */ { - .name = "[ALi ALADDiN-PRO II] PC Chips M729", + .name = "[ALi ALADDiN-PRO II] PCChips M729", .internal_name = "m729", .type = MACHINE_TYPE_SLOT1, .chipset = MACHINE_CHIPSET_ALI_ALADDIN_PRO_II, @@ -17183,7 +17183,7 @@ const machine_t machines[] = { /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC firmware. */ { - .name = "[i440LX] ABIT LX6", + .name = "[i440LX] ABIT AB-LX6", .internal_name = "lx6", .type = MACHINE_TYPE_SLOT1, .chipset = MACHINE_CHIPSET_INTEL_440LX, @@ -17412,7 +17412,7 @@ const machine_t machines[] = { /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC firmware. */ { - .name = "[i440BX] ABIT BF6", + .name = "[i440BX] ABIT AB-BF6", .internal_name = "bf6", .type = MACHINE_TYPE_SLOT1, .chipset = MACHINE_CHIPSET_INTEL_440BX, @@ -17457,7 +17457,7 @@ const machine_t machines[] = { /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC firmware. */ { - .name = "[i440BX] ABIT BX6", + .name = "[i440BX] ABIT AB-BX6", .internal_name = "bx6", .type = MACHINE_TYPE_SLOT1, .chipset = MACHINE_CHIPSET_INTEL_440BX, @@ -17998,7 +17998,7 @@ const machine_t machines[] = { }, /* Has the SiS (5)600 chipset with on-chip KBC. */ { - .name = "[SiS 5600] PC Chips M747", + .name = "[SiS 5600] PCChips M747", .internal_name = "m747", .type = MACHINE_TYPE_SLOT1, .chipset = MACHINE_CHIPSET_SIS_5600, @@ -18879,7 +18879,7 @@ const machine_t machines[] = { /* Has an ITE IT8671F Super I/O chip with on-chip KBC with AMIKey-2 KBC firmware. */ { - .name = "[SMSC VictoryBX-66] PC Chips M773", + .name = "[SMSC VictoryBX-66] PCChips M773", .internal_name = "m773", .type = MACHINE_TYPE_SOCKET370, .chipset = MACHINE_CHIPSET_SMSC_VICTORYBX_66, @@ -18926,7 +18926,7 @@ const machine_t machines[] = { /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA VT82C42N. */ { - .name = "[VIA Apollo Pro] PC Partner APAS3", + .name = "[VIA Apollo Pro] PCPartner APAS3", .internal_name = "apas3", .type = MACHINE_TYPE_SOCKET370, .chipset = MACHINE_CHIPSET_VIA_APOLLO_PRO, @@ -19531,7 +19531,7 @@ machine_has_bus(int m, int bus_flags) if ((bus_flags & MACHINE_BUS_XT_KBD) && !(machines[m].bus_flags & MACHINE_BUS_ISA16) && (!(machines[m].bus_flags & MACHINE_BUS_PS2_PORTS) || - !(strcmp(machine_get_internal_name(), "pc5086")))) + (machines[m].init == machine_xt_pc5086_init))) ret |= MACHINE_BUS_XT_KBD; #ifdef ONLY_AT_KBD_ON_AT_KBC diff --git a/src/mem/catalyst_flash.c b/src/mem/catalyst_flash.c index 5c8812464..da9bfc249 100644 --- a/src/mem/catalyst_flash.c +++ b/src/mem/catalyst_flash.c @@ -9,8 +9,6 @@ * Implementation of the Intel 1 Mbit and 2 Mbit, 8-bit and * 16-bit flash devices. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/mem/i2c_eeprom.c b/src/mem/i2c_eeprom.c index a8ae7ed04..75b13a801 100644 --- a/src/mem/i2c_eeprom.c +++ b/src/mem/i2c_eeprom.c @@ -8,8 +8,6 @@ * * Emulation of the 24Cxx series of I2C EEPROMs. * - * - * * Authors: RichardG, * * Copyright 2020 RichardG. diff --git a/src/mem/intel_flash.c b/src/mem/intel_flash.c index e193f3545..50e8016ce 100644 --- a/src/mem/intel_flash.c +++ b/src/mem/intel_flash.c @@ -9,8 +9,6 @@ * Implementation of the Intel 1 Mbit and 2 Mbit, 8-bit and * 16-bit flash devices. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/mem/mmu_2386.c b/src/mem/mmu_2386.c index ebf062d95..21a5c43a3 100644 --- a/src/mem/mmu_2386.c +++ b/src/mem/mmu_2386.c @@ -1,20 +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. + * 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. * - * Memory handling and MMU. + * Memory handling and MMU. * - * Authors: Sarah Walker, - * Miran Grca, - * Fred N. van Kempen, + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, * - * Copyright 2008-2020 Sarah Walker. - * Copyright 2016-2020 Miran Grca. - * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. */ #include #include @@ -1048,7 +1048,7 @@ do_mmutranslate_2386(uint32_t addr, uint32_t *a64, int num, int write) mem_debug_check_addr(addr, write ? 2 : read_type); for (i = 0; i < num; i++) - a64[i] = (uint64_t) addr; + a64[i] = (uint64_t) addr; if (!(temp_cr0 >> 31)) return; diff --git a/src/mem/nmc93cxx.c b/src/mem/nmc93cxx.c index 50905bae2..17d97591e 100644 --- a/src/mem/nmc93cxx.c +++ b/src/mem/nmc93cxx.c @@ -8,14 +8,12 @@ * * Emulation of National Semiconductors NMC93Cxx EEPROMs. * - * * Authors: Cacodemon345 * * Copyright 2023 Cacodemon345 */ /* Ported over from QEMU */ - #include #include #include diff --git a/src/mem/rom.c b/src/mem/rom.c index f7b2b2b0d..631328913 100644 --- a/src/mem/rom.c +++ b/src/mem/rom.c @@ -12,8 +12,6 @@ * - pc2386 video BIOS is underdumped (16k instead of 24k) * - c386sx16 BIOS fails checksum * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, @@ -28,6 +26,7 @@ #include #include #include +#include #define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" @@ -91,8 +90,9 @@ rom_check(const char *fn) { FILE *fp = NULL; int ret = 0; + char last = fn[strlen(fn) - 1]; - if ((fn[strlen(fn) - 1] == '/') || (fn[strlen(fn) - 1] == '\\')) + if ((last == '/') || (last == '\\')) ret = plat_dir_check((char *) fn); else { fp = fopen(fn, "rb"); @@ -111,7 +111,7 @@ rom_get_full_path(char *dest, const char *fn) dest[0] = 0x00; - if (strstr(fn, "roms/") == fn) { + if (!strncmp(fn, "roms/", 5)) { /* Relative path */ for (rom_path_t *rom_path = &rom_paths; rom_path != NULL; rom_path = rom_path->next) { path_append_filename(temp, rom_path->path, fn + 5); @@ -138,14 +138,13 @@ rom_fopen(const char *fn, char *mode) if ((fn == NULL) || (mode == NULL)) return NULL; - if (strstr(fn, "roms/") == fn) { + if (!strncmp(fn, "roms/", 5)) { /* Relative path */ for (rom_path_t *rom_path = &rom_paths; rom_path != NULL; rom_path = rom_path->next) { path_append_filename(temp, rom_path->path, fn + 5); - if ((fp = plat_fopen(temp, mode)) != NULL) { + if ((fp = plat_fopen(temp, mode)) != NULL) return fp; - } } return fp; @@ -156,16 +155,16 @@ rom_fopen(const char *fn, char *mode) } int -rom_getfile(char *fn, char *s, int size) +rom_getfile(const char *fn, char *s, int size) { char temp[1024]; - if (strstr(fn, "roms/") == fn) { + if (!strncmp(fn, "roms/", 5)) { /* Relative path */ for (rom_path_t *rom_path = &rom_paths; rom_path != NULL; rom_path = rom_path->next) { path_append_filename(temp, rom_path->path, fn + 5); - if (rom_present(temp)) { + if (plat_file_check(temp)) { strncpy(s, temp, size); return 1; } @@ -174,7 +173,7 @@ rom_getfile(char *fn, char *s, int size) return 0; } else { /* Absolute path */ - if (rom_present(fn)) { + if (plat_file_check(fn)) { strncpy(s, fn, size); return 1; } @@ -186,15 +185,25 @@ rom_getfile(char *fn, char *s, int size) int rom_present(const char *fn) { - FILE *fp; + char temp[1024]; - fp = rom_fopen(fn, "rb"); - if (fp != NULL) { - (void) fclose(fp); - return 1; + if (fn == NULL) + return 0; + + if (!strncmp(fn, "roms/", 5)) { + /* Relative path */ + for (rom_path_t *rom_path = &rom_paths; rom_path != NULL; rom_path = rom_path->next) { + path_append_filename(temp, rom_path->path, fn + 5); + + if (plat_file_check(temp)) + return 1; + } + + return 0; + } else { + /* Absolute path */ + return plat_file_check(fn); } - - return 0; } uint8_t @@ -598,13 +607,14 @@ bios_load(const char *fn1, const char *fn2, uint32_t addr, int sz, int off, int */ if (!bios_only) ptr = (flags & FLAG_AUX) ? rom : rom_reset(addr, sz); + else + return (!fn1 || rom_present(fn1)) && (!fn2 || rom_present(fn2)); if (!(flags & FLAG_AUX) && ((addr + sz) > 0x00100000)) sz = 0x00100000 - addr; #ifdef ENABLE_ROM_LOG - if (!bios_only) - rom_log("%sing %i bytes of %sBIOS starting with ptr[%08X] (ptr = %08X)\n", (bios_only) ? "Check" : "Load", sz, (flags & FLAG_AUX) ? "auxiliary " : "", addr - biosaddr, ptr); + rom_log("%sing %i bytes of %sBIOS starting with ptr[%08X] (ptr = %08X)\n", (bios_only) ? "Check" : "Load", sz, (flags & FLAG_AUX) ? "auxiliary " : "", addr - biosaddr, ptr); #endif if (flags & FLAG_INT) @@ -616,7 +626,7 @@ bios_load(const char *fn1, const char *fn2, uint32_t addr, int sz, int off, int ret = rom_load_linear(fn1, addr - biosaddr, sz, off, ptr); } - if (!bios_only && (flags & FLAG_REP) && (old_sz >= 65536) && (sz < old_sz)) { + if ((flags & FLAG_REP) && (old_sz >= 65536) && (sz < old_sz)) { old_sz /= sz; for (int i = 0; i < (old_sz - 1); i++) { rom_log("Copying ptr[%08X] to ptr[%08X]\n", addr - biosaddr, i * sz); @@ -624,7 +634,7 @@ bios_load(const char *fn1, const char *fn2, uint32_t addr, int sz, int off, int } } - if (!bios_only && ret && !(flags & FLAG_AUX)) + if (ret && !(flags & FLAG_AUX)) bios_add(); return ret; @@ -633,42 +643,28 @@ bios_load(const char *fn1, const char *fn2, uint32_t addr, int sz, int off, int int bios_load_linear_combined(const char *fn1, const char *fn2, int sz, UNUSED(int off)) { - uint8_t ret = 0; - - ret = bios_load_linear(fn1, 0x000f0000, 131072, 128); - ret &= bios_load_aux_linear(fn2, 0x000e0000, sz - 65536, 128); - - return ret; + return bios_load_linear(fn1, 0x000f0000, 131072, 128) && \ + bios_load_aux_linear(fn2, 0x000e0000, sz - 65536, 128); } int bios_load_linear_combined2(const char *fn1, const char *fn2, const char *fn3, const char *fn4, const char *fn5, int sz, int off) { - uint8_t ret = 0; - - ret = bios_load_linear(fn3, 0x000f0000, 262144, off); - ret &= bios_load_aux_linear(fn1, 0x000d0000, 65536, off); - ret &= bios_load_aux_linear(fn2, 0x000c0000, 65536, off); - ret &= bios_load_aux_linear(fn4, 0x000e0000, sz - 196608, off); - if (fn5 != NULL) - ret &= bios_load_aux_linear(fn5, 0x000ec000, 16384, 0); - - return ret; + return bios_load_linear(fn3, 0x000f0000, 262144, off) && \ + bios_load_aux_linear(fn1, 0x000d0000, 65536, off) && \ + bios_load_aux_linear(fn2, 0x000c0000, 65536, off) && \ + bios_load_aux_linear(fn4, 0x000e0000, sz - 196608, off) && \ + (!fn5 || bios_load_aux_linear(fn5, 0x000ec000, 16384, 0)); } int bios_load_linear_combined2_ex(const char *fn1, const char *fn2, const char *fn3, const char *fn4, const char *fn5, int sz, int off) { - uint8_t ret = 0; - - ret = bios_load_linear(fn3, 0x000e0000, 262144, off); - ret &= bios_load_aux_linear(fn1, 0x000c0000, 65536, off); - ret &= bios_load_aux_linear(fn2, 0x000d0000, 65536, off); - ret &= bios_load_aux_linear(fn4, 0x000f0000, sz - 196608, off); - if (fn5 != NULL) - ret &= bios_load_aux_linear(fn5, 0x000fc000, 16384, 0); - - return ret; + return bios_load_linear(fn3, 0x000e0000, 262144, off) && \ + bios_load_aux_linear(fn1, 0x000c0000, 65536, off) && \ + bios_load_aux_linear(fn2, 0x000d0000, 65536, off) && \ + bios_load_aux_linear(fn4, 0x000f0000, sz - 196608, off) && \ + (!fn5 || bios_load_aux_linear(fn5, 0x000fc000, 16384, 0)); } int diff --git a/src/mem/row.c b/src/mem/row.c index 572df7f47..02839b848 100644 --- a/src/mem/row.c +++ b/src/mem/row.c @@ -1,16 +1,16 @@ /* - * 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. * - * DRAM row handling. + * DRAM row handling. * - * Authors: Miran Grca, + * Authors: Miran Grca, * - * Copyright 2016-2020 Miran Grca. + * Copyright 2016-2020 Miran Grca. */ #include #include @@ -266,9 +266,9 @@ row_init(const device_t *info) pages[c].write_w = NULL; pages[c].write_l = NULL; #ifdef USE_NEW_DYNAREC - pages[c].evict_prev = EVICT_NOT_IN_LIST; - pages[c].byte_dirty_mask = &byte_dirty_mask[c * 64]; - pages[c].byte_code_present_mask = &byte_code_present_mask[c * 64]; + pages[c].evict_prev = EVICT_NOT_IN_LIST; + pages[c].byte_dirty_mask = &byte_dirty_mask[c * 64]; + pages[c].byte_code_present_mask = &byte_code_present_mask[c * 64]; #endif } diff --git a/src/mem/spd.c b/src/mem/spd.c index 01cd7b464..f3a61297b 100644 --- a/src/mem/spd.c +++ b/src/mem/spd.c @@ -8,8 +8,6 @@ * * Emulation of SPD (Serial Presence Detect) devices. * - * - * * Authors: RichardG, * * Copyright 2020 RichardG. diff --git a/src/mem/sst_flash.c b/src/mem/sst_flash.c index 34bfae83a..5db1e33de 100644 --- a/src/mem/sst_flash.c +++ b/src/mem/sst_flash.c @@ -8,8 +8,6 @@ * * Implementation of an SST flash chip. * - * - * * Authors: Miran Grca, * Jasmine Iwanek, * @@ -524,7 +522,7 @@ sst_init(const device_t *info) dev->is_39 = 1; dev->size = info->local & 0xffff0000; - if ((dev->size == 0x20000) && (strstr(machine_get_internal_name_ex(machine), "xi8088")) && !xi8088_bios_128kb()) + if ((dev->size == 0x20000) && ((machines[machine].init == machine_xt_xi8088_init) && !xi8088_bios_128kb())) dev->size = 0x10000; dev->mask = dev->size - 1; diff --git a/src/network/net_3c501.c b/src/network/net_3c501.c index f5809afb1..78c71ca88 100644 --- a/src/network/net_3c501.c +++ b/src/network/net_3c501.c @@ -9,8 +9,6 @@ * Implementation of the following network controller: * - 3Com Etherlink 3c500/3c501 (ISA 8-bit). * - * - * * Based on @(#)Dev3C501.cpp Oracle (VirtualBox) * * Authors: TheCollector1995, diff --git a/src/network/net_3c503.c b/src/network/net_3c503.c index ea64633bc..3c1f1b041 100644 --- a/src/network/net_3c503.c +++ b/src/network/net_3c503.c @@ -9,8 +9,6 @@ * Implementation of the following network controllers: * - 3Com Etherlink II 3c503 (ISA 8-bit). * - * - * * Based on @(#)3c503.cpp Carl (MAME) * * Authors: TheCollector1995, diff --git a/src/network/net_dp8390.c b/src/network/net_dp8390.c index a0e0e7129..7f3490877 100644 --- a/src/network/net_dp8390.c +++ b/src/network/net_dp8390.c @@ -7,8 +7,6 @@ * Emulation of the DP8390 Network Interface Controller used by * the WD family, NE1000/NE2000 family, and 3Com 3C503 NIC's. * - * - * * Authors: Miran Grca, * Bochs project, * diff --git a/src/network/net_modem.c b/src/network/net_modem.c index 24869349f..20d3a03d1 100644 --- a/src/network/net_modem.c +++ b/src/network/net_modem.c @@ -8,8 +8,6 @@ * * Hayes AT-compliant modem emulation. * - * - * * Authors: Cacodemon345 * The DOSBox Team * @@ -17,7 +15,6 @@ * Copyright (C) 2022 The DOSBox Staging Team * Copyright (C) 2002-2021 The DOSBox Team */ - #include #include #include diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index 0174ef098..0ce0190ac 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -13,8 +13,6 @@ * - Realtek RTL8019AS (ISA 16-bit, PnP); * - Realtek RTL8029AS (PCI). * - * - * * Based on @(#)ne2k.cc v1.56.2.1 2004/02/02 22:37:22 cbothamy * * Authors: Fred N. van Kempen, diff --git a/src/network/net_netswitch.c b/src/network/net_netswitch.c index 336895dc6..1cd0a81a7 100644 --- a/src/network/net_netswitch.c +++ b/src/network/net_netswitch.c @@ -1,21 +1,17 @@ /* -* 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. -* -* Network Switch network driver -* -* -* -* Authors: cold-brewed -* -* Copyright 2024 cold-brewed + * 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. + * + * Network Switch network driver + * + * Authors: cold-brewed + * + * Copyright 2024 cold-brewed */ - - #include #include #include @@ -405,6 +401,7 @@ net_netswitch_init(const netcard_t *card, const uint8_t *mac_addr, void *priv, c memcpy(ns_args.mac_addr, net_netswitch->mac_addr, 6); /* The remote switch hostname */ strncpy(ns_args.nrs_hostname, netcard->nrs_hostname, sizeof(ns_args.nrs_hostname) - 1); + ns_args.nrs_hostname[127] = 0x00; net_switch_log("%s Net Switch: Starting up virtual switch with group %d, flags %d\n", net_netswitch->switch_type, ns_args.group, ns_args.flags); diff --git a/src/network/net_null.c b/src/network/net_null.c index 6d5f68e46..4b1f03e3f 100644 --- a/src/network/net_null.c +++ b/src/network/net_null.c @@ -1,20 +1,17 @@ /* -* 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. -* -* Null network driver -* -* -* -* Authors: cold-brewed -* -* Copyright 2023 The 86Box development team -*/ - + * 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. + * + * Null network driver + * + * Authors: cold-brewed + * + * Copyright 2023 The 86Box development team + */ #include #include #include diff --git a/src/network/net_pcap.c b/src/network/net_pcap.c index 2af34d786..e0c6804f4 100644 --- a/src/network/net_pcap.c +++ b/src/network/net_pcap.c @@ -6,8 +6,6 @@ * * Handle WinPcap library processing. * - * - * * Authors: Fred N. van Kempen, * * Copyright 2017-2019 Fred N. van Kempen. diff --git a/src/network/net_pcnet.c b/src/network/net_pcnet.c index 16fd7c65c..0c97d1078 100644 --- a/src/network/net_pcnet.c +++ b/src/network/net_pcnet.c @@ -4,11 +4,11 @@ * PC systems and compatibles from 1981 through fairly recent * system designs based on the PCI bus. * + * This file is part of the 86Box distribution. + * * Emulation of the AMD PCnet LANCE NIC controller for both the ISA, VLB, * and PCI buses. * - * - * * Authors: Miran Grca, * TheCollector1995, * Antony T Curtis diff --git a/src/network/net_plip.c b/src/network/net_plip.c index 5eacc5536..36df49153 100644 --- a/src/network/net_plip.c +++ b/src/network/net_plip.c @@ -12,8 +12,6 @@ * packet driver. PLIP is not particularly fast, as it's a 4-bit * half-duplex protocol operating over SPP. * - * - * * Authors: RichardG, * Copyright 2020 RichardG. */ diff --git a/src/network/net_rtl8139.c b/src/network/net_rtl8139.c index 41ce86f6b..5f2c85b03 100644 --- a/src/network/net_rtl8139.c +++ b/src/network/net_rtl8139.c @@ -835,7 +835,7 @@ rtl8139_do_receive(void *priv, uint8_t *buf, int size_) uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK; /* write VLAN info to descriptor variables. */ - if (s->CpCmd & CPlusRxVLAN && bswap16(*((uint16_t *) &buf[ETH_ALEN * 2])) == 0x8100) { + if (s->CpCmd & CPlusRxVLAN && bswap16(AS_U16(buf[ETH_ALEN * 2])) == 0x8100) { dot1q_buf = &buf[ETH_ALEN * 2]; size -= VLAN_HLEN; /* if too small buffer, use the tailroom added duing expansion */ @@ -849,7 +849,7 @@ rtl8139_do_receive(void *priv, uint8_t *buf, int size_) rtl8139_log("C+ Rx mode : extracted vlan tag with tci: " "%u\n", - bswap16(*((uint16_t *) &dot1q_buf[ETHER_TYPE_LEN]))); + bswap16(AS_U16(dot1q_buf[ETHER_TYPE_LEN]))); } else { /* reset VLAN tag flag */ rxdw1 &= ~CP_RX_TAVA; diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index 9bf1f63d4..4f61a55a8 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -11,8 +11,6 @@ * Some of the code was borrowed from libvdeslirp * * - * - * * Authors: Fred N. van Kempen, * RichardG, * diff --git a/src/network/net_tap.c b/src/network/net_tap.c index 762f68b60..48721a9d2 100644 --- a/src/network/net_tap.c +++ b/src/network/net_tap.c @@ -13,7 +13,6 @@ * * Authors: Doug Johnson * - * * Copyright 2023 Doug Johnson * * Redistribution and use in source and binary forms, with @@ -46,7 +45,6 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - #ifdef _WIN32 # error TAP networking is only supported on Linux #endif diff --git a/src/network/net_wd8003.c b/src/network/net_wd8003.c index 890b221e2..100391eb0 100644 --- a/src/network/net_wd8003.c +++ b/src/network/net_wd8003.c @@ -11,8 +11,6 @@ * - SMC/WD 8013EBT (ISA 16-bit); * - SMC/WD 8013EP/A (MCA). * - * - * * Authors: Fred N. van Kempen, * TheCollector1995, * Miran Grca, diff --git a/src/network/netswitch.c b/src/network/netswitch.c index 54815a682..1ec2c5e6f 100644 --- a/src/network/netswitch.c +++ b/src/network/netswitch.c @@ -1,21 +1,17 @@ /* -* 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. -* -* Network Switch backend -* -* -* -* Authors: cold-brewed -* -* Copyright 2024 cold-brewed -*/ - - + * 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. + * + * Network Switch backend + * + * Authors: cold-brewed + * + * Copyright 2024 cold-brewed + */ #include #include #include @@ -246,6 +242,7 @@ ns_open(struct ns_open_args *open_args) { /* Remote switch hostname */ strncpy(conn->nrs_hostname, open_args->nrs_hostname, sizeof(conn->nrs_hostname) - 1); + conn->nrs_hostname[127] = 0x00; /* Switch type */ if(conn->switch_type == SWITCH_TYPE_REMOTE) { diff --git a/src/network/netswitch.h b/src/network/netswitch.h index 02534ff30..69062b66c 100644 --- a/src/network/netswitch.h +++ b/src/network/netswitch.h @@ -1,20 +1,17 @@ /* -* 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. -* -* Network Switch backend -* -* -* -* Authors: cold-brewed -* -* Copyright 2024 cold-brewed -*/ - + * 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. + * + * Network Switch backend + * + * Authors: cold-brewed + * + * Copyright 2024 cold-brewed + */ #ifndef NET_SWITCH_H #define NET_SWITCH_H diff --git a/src/network/network.c b/src/network/network.c index 661da7250..3f854f356 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -10,8 +10,6 @@ * it should be malloc'ed and then linked to the NETCARD def. * Will be done later. * - * - * * Authors: Fred N. van Kempen, * * Copyright 2017-2019 Fred N. van Kempen. diff --git a/src/network/pb_encode.c b/src/network/pb_encode.c index 7f5620125..a4e30b471 100644 --- a/src/network/pb_encode.c +++ b/src/network/pb_encode.c @@ -53,7 +53,8 @@ static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, si { pb_byte_t *dest = (pb_byte_t*)stream->state; stream->state = dest + count; - + + if ((dest != NULL) && (buf != NULL)) memcpy(dest, buf, count * sizeof(pb_byte_t)); return true; diff --git a/src/nvr.c b/src/nvr.c index b6bf2a5a5..ba4a12aa4 100644 --- a/src/nvr.c +++ b/src/nvr.c @@ -6,8 +6,6 @@ * * Implement a generic NVRAM/CMOS/RTC device. * - * - * * Authors: Fred N. van Kempen, , * David Hrdlička, * diff --git a/src/nvr_at.c b/src/nvr_at.c index 6853867ec..ae7bd8bb4 100644 --- a/src/nvr_at.c +++ b/src/nvr_at.c @@ -1213,7 +1213,7 @@ nvr_at_init(const device_t *info) } /* This is a hack but it is required for the machine to boot properly, no idea why. */ - if (nvr->is_new && !strcmp(machine_get_internal_name(), "spitfire")) + if (nvr->is_new && (machines[machine].init == machine_at_spitfire_init)) nvr->regs[0x33] = nvr->regs[0x34] = 0xff; return nvr; diff --git a/src/nvr_ps2.c b/src/nvr_ps2.c index febf6c165..9698f5fae 100644 --- a/src/nvr_ps2.c +++ b/src/nvr_ps2.c @@ -8,8 +8,6 @@ * * Handling of the PS/2 series CMOS devices. * - * - * * Authors: Fred N. van Kempen, * Sarah Walker, * diff --git a/src/pci.c b/src/pci.c index 94ab9d5f2..16e8cdb4f 100644 --- a/src/pci.c +++ b/src/pci.c @@ -8,8 +8,6 @@ * * Implementation the PCI bus. * - * - * * Authors: Miran Grca, * * Copyright 2023 Miran Grca. diff --git a/src/pic.c b/src/pic.c index 446ea1361..a39933939 100644 --- a/src/pic.c +++ b/src/pic.c @@ -9,8 +9,6 @@ * Implementation of the Intel PIC chip emulation, partially * ported from reenigne's XTCE. * - * - * * Authors: Andrew Jenner, * Miran Grca, * @@ -254,7 +252,7 @@ void pic_reset(void) { int is_at = IS_AT(machine); - is_at = is_at || !strcmp(machine_get_internal_name(), "xi8088"); + is_at = is_at || (machines[machine].init == machine_xt_xi8088_init); memset(&pic, 0, sizeof(pic_t)); memset(&pic2, 0, sizeof(pic_t)); diff --git a/src/pit.c b/src/pit.c index b99fed799..7c58a4b67 100644 --- a/src/pit.c +++ b/src/pit.c @@ -9,8 +9,6 @@ * Implementation of the Intel 8253/8254 Programmable Interval * Timer. * - * - * * Authors: Miran Grca, * * Copyright 2019 Miran Grca. diff --git a/src/pit_fast.c b/src/pit_fast.c index b92b59f3c..f8df2a7c4 100644 --- a/src/pit_fast.c +++ b/src/pit_fast.c @@ -9,8 +9,6 @@ * Implementation of the Intel 8253/8254 Programmable Interval * Timer. * - * - * * Authors: Miran Grca, * * Copyright 2019 Miran Grca. diff --git a/src/port_6x.c b/src/port_6x.c index b8183d651..0dc9bdbdd 100644 --- a/src/port_6x.c +++ b/src/port_6x.c @@ -9,8 +9,6 @@ * Implementation of Ports 61, 62, and 63 used by various * machines. * - * - * * Authors: Miran Grca, * * Copyright 2021 Miran Grca. diff --git a/src/port_92.c b/src/port_92.c index d1a53a321..23595eeb9 100644 --- a/src/port_92.c +++ b/src/port_92.c @@ -9,8 +9,6 @@ * Implementation of Port 92 used by PS/2 machines and 386+ * clones. * - * - * * Authors: Miran Grca, * * Copyright 2019 Miran Grca. diff --git a/src/printer/png.c b/src/printer/png.c index c7443252b..52d939673 100644 --- a/src/printer/png.c +++ b/src/printer/png.c @@ -6,8 +6,6 @@ * * Provide centralized access to the PNG image handler. * - * - * * Authors: Fred N. van Kempen, * * Copyright 2018 Fred N. van Kempen. diff --git a/src/printer/prt_cpmap.c b/src/printer/prt_cpmap.c index 153008f35..370e258ce 100644 --- a/src/printer/prt_cpmap.c +++ b/src/printer/prt_cpmap.c @@ -6,8 +6,6 @@ * * Various ASCII to Unicode maps, for the various codepages. * - * - * * Authors: Michael Drüing, * Fred N. van Kempen, * diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index 8fb6a1059..a24072971 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -6,8 +6,6 @@ * * Implementation of the Generic ESC/P 2 Dot-Matrix printer. * - * - * * Authors: Michael Drüing, * Fred N. van Kempen, * diff --git a/src/printer/prt_ps.c b/src/printer/prt_ps.c index 38c8053c2..3a3230394 100644 --- a/src/printer/prt_ps.c +++ b/src/printer/prt_ps.c @@ -9,15 +9,12 @@ * Implementation of a generic PostScript printer and a * generic PCL 5e printer. * - * - * * Authors: David Hrdlička, * Cacodemon345 * * Copyright 2019 David Hrdlička. * Copyright 2024 Cacodemon345. */ - #include #include #include diff --git a/src/printer/prt_text.c b/src/printer/prt_text.c index 41d3737d1..af601af75 100644 --- a/src/printer/prt_text.c +++ b/src/printer/prt_text.c @@ -13,8 +13,6 @@ * printer mechanics. This would lead to a page being 66 lines * of 80 characters each. * - * - * * Authors: Fred N. van Kempen, * * Copyright 2018-2019 Fred N. van Kempen. diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 2bc3eacbb..a48fde924 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -540,6 +540,7 @@ main(int argc, char *argv[]) #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); #endif + QApplication::setAttribute(Qt::AA_UseDesktopOpenGL); QApplication app(argc, argv); QLocale::setDefault(QLocale::C); diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index ced74024b..b74b74202 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -75,11 +75,7 @@ extern int video_focus_dim; extern int video_refresh_rate; const char* vertex_shader_default_tex_src = -#ifdef __APPLE__ "#version 150\n" -#else - "#version 130\n" -#endif "\n" "in vec4 VertexCoord;\n" "in vec2 TexCoord;\n" @@ -93,11 +89,7 @@ const char* vertex_shader_default_tex_src = "}\n"; const char* fragment_shader_default_tex_src = -#ifdef __APPLE__ "#version 150\n" -#else - "#version 130\n" -#endif "\n" "in vec2 texCoord;\n" "uniform sampler2D Texture;\n" @@ -111,11 +103,7 @@ const char* fragment_shader_default_tex_src = "}\n"; const char* vertex_shader_default_color_src = -#ifdef __APPLE__ "#version 150\n" -#else - "#version 130\n" -#endif "\n" "in vec4 VertexCoord;\n" "in vec4 Color;\n" @@ -129,11 +117,7 @@ const char* vertex_shader_default_color_src = "}\n"; const char* fragment_shader_default_color_src = -#ifdef __APPLE__ "#version 150\n" -#else - "#version 130\n" -#endif "\n" "in vec4 color;\n" "\n" @@ -1223,6 +1207,9 @@ OpenGLRenderer::resizeEvent(QResizeEvent *event) destination.y(), destination.width(), destination.height()); + + if (video_framerate == -1) + render(); } void diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index a0c2aa502..ad49e5e7c 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -64,6 +64,8 @@ # include #endif +#include + #ifdef Q_OS_OPENBSD # include #endif @@ -250,6 +252,21 @@ plat_dir_check(char *path) return fi.isDir() ? 1 : 0; } +int +plat_file_check(const char *path) +{ +#ifdef _WIN32 + auto data = QString::fromUtf8(path).toStdWString(); + auto res = GetFileAttributesW(data.c_str()); + return (res != INVALID_FILE_ATTRIBUTES) && !(res & FILE_ATTRIBUTE_DIRECTORY); +#else + struct stat stats; + if (stat(path, &stats) < 0) + return 0; + return !S_ISDIR(stats.st_mode); +#endif +} + int plat_getcwd(char *bufp, int max) { diff --git a/src/qt/qt_settingsfloppycdrom.cpp b/src/qt/qt_settingsfloppycdrom.cpp index 495fb74e8..6ec130044 100644 --- a/src/qt/qt_settingsfloppycdrom.cpp +++ b/src/qt/qt_settingsfloppycdrom.cpp @@ -34,43 +34,41 @@ extern "C" { #include <86box/cdrom.h> } -#include - #include "qt_models_common.hpp" #include "qt_harddrive_common.hpp" #include "qt_settings_bus_tracking.hpp" #include "qt_progsettings.hpp" -static void -setFloppyType(QAbstractItemModel *model, const QModelIndex &idx, int type) +void +SettingsFloppyCDROM::setFloppyType(QAbstractItemModel *model, const QModelIndex &idx, int type) { QIcon icon; if (type == 0) - icon = QIcon(":/settings/qt/icons/floppy_disabled.ico"); + icon = floppy_disabled_icon; else if (type >= 1 && type <= 6) - icon = QIcon(":/settings/qt/icons/floppy_525.ico"); + icon = floppy_525_icon; else - icon = QIcon(":/settings/qt/icons/floppy_35.ico"); + icon = floppy_35_icon; model->setData(idx, QObject::tr(fdd_getname(type))); model->setData(idx, type, Qt::UserRole); model->setData(idx, icon, Qt::DecorationRole); } -static void -setCDROMBus(QAbstractItemModel *model, const QModelIndex &idx, uint8_t bus, uint8_t channel) +void +SettingsFloppyCDROM::setCDROMBus(QAbstractItemModel *model, const QModelIndex &idx, uint8_t bus, uint8_t channel) { QIcon icon; switch (bus) { case CDROM_BUS_DISABLED: - icon = QIcon(":/settings/qt/icons/cdrom_disabled.ico"); + icon = cdrom_disabled_icon; break; case CDROM_BUS_ATAPI: case CDROM_BUS_SCSI: case CDROM_BUS_MITSUMI: case CDROM_BUS_MKE: - icon = QIcon(":/settings/qt/icons/cdrom.ico"); + icon = cdrom_icon; break; } @@ -116,6 +114,10 @@ SettingsFloppyCDROM::SettingsFloppyCDROM(QWidget *parent) { ui->setupUi(this); + floppy_disabled_icon = QIcon(":/settings/qt/icons/floppy_disabled.ico"); + floppy_525_icon = QIcon(":/settings/qt/icons/floppy_525.ico"); + floppy_35_icon = QIcon(":/settings/qt/icons/floppy_35.ico"); + auto *model = ui->comboBoxFloppyType->model(); int i = 0; while (true) { @@ -186,6 +188,9 @@ SettingsFloppyCDROM::SettingsFloppyCDROM(QWidget *parent) // Manually trigger the row changed event to ensure audio selection is updated onFloppyRowChanged(model->index(0, 0)); + cdrom_disabled_icon = QIcon(":/settings/qt/icons/cdrom_disabled.ico"); + cdrom_icon = QIcon(":/settings/qt/icons/cdrom.ico"); + Harddrives::populateCDROMBuses(ui->comboBoxBus->model()); model = ui->comboBoxSpeed->model(); for (int i = 0; i < 72; i++) diff --git a/src/qt/qt_settingsfloppycdrom.hpp b/src/qt/qt_settingsfloppycdrom.hpp index 4c69d5cc3..9a53dd88f 100644 --- a/src/qt/qt_settingsfloppycdrom.hpp +++ b/src/qt/qt_settingsfloppycdrom.hpp @@ -2,6 +2,7 @@ #define QT_SETTINGSFLOPPYCDROM_HPP #include +#include namespace Ui { class SettingsFloppyCDROM; @@ -37,7 +38,15 @@ private slots: private: Ui::SettingsFloppyCDROM *ui; + void setFloppyType(QAbstractItemModel *model, const QModelIndex &idx, int type); + void setCDROMBus(QAbstractItemModel *model, const QModelIndex &idx, uint8_t bus, uint8_t channel); void enableCurrentlySelectedChannel(); + + QIcon floppy_disabled_icon; + QIcon floppy_525_icon; + QIcon floppy_35_icon; + QIcon cdrom_disabled_icon; + QIcon cdrom_icon; }; #endif // QT_SETTINGSFLOPPYCDROM_HPP diff --git a/src/qt/qt_settingsfloppycdrom.ui b/src/qt/qt_settingsfloppycdrom.ui index ff54a5020..0c9283834 100644 --- a/src/qt/qt_settingsfloppycdrom.ui +++ b/src/qt/qt_settingsfloppycdrom.ui @@ -66,69 +66,48 @@ - - - - - - - Type: - - - - - - - 30 - - - - - - - Turbo timings - - - - - - - Check BPB - - - - + + + + + Type: + + - - - - - - Audio: - - - - - - - 10 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + + 30 + + + + + + + Turbo timings + + + + + + + Check BPB + + + + + + + Audio: + + + + + + + 30 + + diff --git a/src/qt/qt_settingsharddisks.cpp b/src/qt/qt_settingsharddisks.cpp index 6d82f2b77..40142f4d2 100644 --- a/src/qt/qt_settingsharddisks.cpp +++ b/src/qt/qt_settingsharddisks.cpp @@ -44,6 +44,8 @@ const int DataBusChannel = Qt::UserRole + 1; const int DataBusPrevious = Qt::UserRole + 2; const int DataBusChannelPrevious = Qt::UserRole + 3; +QIcon hard_disk_icon; + #if 0 static void normalize_hd_list() @@ -78,28 +80,31 @@ addRow(QAbstractItemModel *model, hard_disk_t *hd) model->insertRow(row); + auto busIndex = model->index(row, ColumnBus); QString busName = Harddrives::BusChannelName(hd->bus_type, hd->channel); - model->setData(model->index(row, ColumnBus), busName); - model->setData(model->index(row, ColumnBus), QIcon(":/settings/qt/icons/hard_disk.ico"), Qt::DecorationRole); - model->setData(model->index(row, ColumnBus), hd->bus_type, DataBus); - model->setData(model->index(row, ColumnBus), hd->bus_type, DataBusPrevious); - model->setData(model->index(row, ColumnBus), hd->channel, DataBusChannel); - model->setData(model->index(row, ColumnBus), hd->channel, DataBusChannelPrevious); + model->setData(busIndex, busName); + model->setData(busIndex, hard_disk_icon, Qt::DecorationRole); + model->setData(busIndex, hd->bus_type, DataBus); + model->setData(busIndex, hd->bus_type, DataBusPrevious); + model->setData(busIndex, hd->channel, DataBusChannel); + model->setData(busIndex, hd->channel, DataBusChannelPrevious); Harddrives::busTrackClass->device_track(1, DEV_HDD, hd->bus_type, hd->channel); + auto filenameIndex = model->index(row, ColumnFilename); QString fileName = hd->fn; if (fileName.startsWith(userPath, Qt::CaseInsensitive)) - model->setData(model->index(row, ColumnFilename), fileName.mid(userPath.size())); + model->setData(filenameIndex, fileName.mid(userPath.size())); else - model->setData(model->index(row, ColumnFilename), fileName); + model->setData(filenameIndex, fileName); - model->setData(model->index(row, ColumnFilename), fileName, Qt::UserRole); + model->setData(filenameIndex, fileName, Qt::UserRole); model->setData(model->index(row, ColumnCylinders), hd->tracks); model->setData(model->index(row, ColumnHeads), hd->hpc); model->setData(model->index(row, ColumnSectors), hd->spt); model->setData(model->index(row, ColumnSize), (hd->tracks * hd->hpc * hd->spt) >> 11); - model->setData(model->index(row, ColumnSpeed), QObject::tr(hdd_preset_getname(hd->speed_preset))); - model->setData(model->index(row, ColumnSpeed), hd->speed_preset, Qt::UserRole); + auto speedIndex = model->index(row, ColumnSpeed); + model->setData(speedIndex, QObject::tr(hdd_preset_getname(hd->speed_preset))); + model->setData(speedIndex, hd->speed_preset, Qt::UserRole); } SettingsHarddisks::SettingsHarddisks(QWidget *parent) @@ -108,6 +113,8 @@ SettingsHarddisks::SettingsHarddisks(QWidget *parent) { ui->setupUi(this); + hard_disk_icon = QIcon(":/settings/qt/icons/hard_disk.ico"); + QAbstractItemModel *model = new QStandardItemModel(0, 7, this); model->setHeaderData(ColumnBus, Qt::Horizontal, tr("Bus")); model->setHeaderData(ColumnFilename, Qt::Horizontal, tr("File")); diff --git a/src/qt/qt_settingsinput.cpp b/src/qt/qt_settingsinput.cpp index 50e3662e9..c540aa2ed 100644 --- a/src/qt/qt_settingsinput.cpp +++ b/src/qt/qt_settingsinput.cpp @@ -123,7 +123,7 @@ SettingsInput::onCurrentMachineChanged(int machineId) int ikbd = (i == KEYBOARD_TYPE_INTERNAL); int pc5086_filter = (strstr(keyboard_get_internal_name(i), "ps") && - strstr(machine_get_internal_name_ex(machineId), "pc5086")); + machines[machineId].init == machine_xt_pc5086_init); if ((ikbd != has_int_kbd) || !device_is_valid(dev, machineId) || pc5086_filter) continue; diff --git a/src/qt/qt_settingsotherremovable.cpp b/src/qt/qt_settingsotherremovable.cpp index 4ba07161c..f2fa3c675 100644 --- a/src/qt/qt_settingsotherremovable.cpp +++ b/src/qt/qt_settingsotherremovable.cpp @@ -26,8 +26,6 @@ extern "C" { #include <86box/rdisk.h> } -#include - #include "qt_models_common.hpp" #include "qt_harddrive_common.hpp" #include "qt_settings_bus_tracking.hpp" @@ -47,17 +45,17 @@ rdiskDriveTypeName(int i) rdisk_drive_types[i].revision); } -static void -setMOBus(QAbstractItemModel *model, const QModelIndex &idx, uint8_t bus, uint8_t channel) +void +SettingsOtherRemovable::setMOBus(QAbstractItemModel *model, const QModelIndex &idx, uint8_t bus, uint8_t channel) { QIcon icon; switch (bus) { case MO_BUS_DISABLED: - icon = QIcon(":/settings/qt/icons/mo_disabled.ico"); + icon = mo_disabled_icon; break; case MO_BUS_ATAPI: case MO_BUS_SCSI: - icon = QIcon(":/settings/qt/icons/mo.ico"); + icon = mo_icon; break; default: @@ -71,17 +69,17 @@ setMOBus(QAbstractItemModel *model, const QModelIndex &idx, uint8_t bus, uint8_t model->setData(i, icon, Qt::DecorationRole); } -static void -setRDiskBus(QAbstractItemModel *model, const QModelIndex &idx, uint8_t bus, uint8_t channel) +void +SettingsOtherRemovable::setRDiskBus(QAbstractItemModel *model, const QModelIndex &idx, uint8_t bus, uint8_t channel) { QIcon icon; switch (bus) { case RDISK_BUS_DISABLED: - icon = QIcon(":/settings/qt/icons/rdisk_disabled.ico"); + icon = rdisk_disabled_icon; break; case RDISK_BUS_ATAPI: case RDISK_BUS_SCSI: - icon = QIcon(":/settings/qt/icons/rdisk.ico"); + icon = rdisk_icon; break; default: @@ -123,6 +121,9 @@ SettingsOtherRemovable::SettingsOtherRemovable(QWidget *parent) { ui->setupUi(this); + mo_disabled_icon = QIcon(":/settings/qt/icons/mo_disabled.ico"); + mo_icon = QIcon(":/settings/qt/icons/mo.ico"); + Harddrives::populateRemovableBuses(ui->comboBoxMOBus->model()); ui->comboBoxMOBus->model()->removeRows(3, ui->comboBoxMOBus->model()->rowCount() - 3); auto *model = ui->comboBoxMOType->model(); @@ -147,6 +148,9 @@ SettingsOtherRemovable::SettingsOtherRemovable(QWidget *parent) connect(ui->tableViewMO->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &SettingsOtherRemovable::onMORowChanged); ui->tableViewMO->setCurrentIndex(model->index(0, 0)); + rdisk_disabled_icon = QIcon(":/settings/qt/icons/rdisk_disabled.ico"); + rdisk_icon = QIcon(":/settings/qt/icons/rdisk.ico"); + Harddrives::populateRemovableBuses(ui->comboBoxRDiskBus->model()); if ((ui->comboBoxRDiskBus->model()->rowCount() - 3) > 0) ui->comboBoxRDiskBus->model()->removeRows(3, ui->comboBoxRDiskBus->model()->rowCount() - 3); diff --git a/src/qt/qt_settingsotherremovable.hpp b/src/qt/qt_settingsotherremovable.hpp index 79fcfbf3f..2c7a4e80e 100644 --- a/src/qt/qt_settingsotherremovable.hpp +++ b/src/qt/qt_settingsotherremovable.hpp @@ -2,6 +2,7 @@ #define QT_SETTINGSOTHERREMOVABLE_HPP #include +#include namespace Ui { class SettingsOtherRemovable; @@ -37,8 +38,15 @@ private slots: private: Ui::SettingsOtherRemovable *ui; + void setMOBus(QAbstractItemModel *model, const QModelIndex &idx, uint8_t bus, uint8_t channel); + void setRDiskBus(QAbstractItemModel *model, const QModelIndex &idx, uint8_t bus, uint8_t channel); void enableCurrentlySelectedChannel_MO(); void enableCurrentlySelectedChannel_RDisk(); + + QIcon mo_disabled_icon; + QIcon mo_icon; + QIcon rdisk_disabled_icon; + QIcon rdisk_icon; }; #endif // QT_SETTINGSOTHERREMOVABLE_HPP diff --git a/src/qt/qt_softwarerenderer.cpp b/src/qt/qt_softwarerenderer.cpp index bb6c7508b..dcc0799dd 100644 --- a/src/qt/qt_softwarerenderer.cpp +++ b/src/qt/qt_softwarerenderer.cpp @@ -21,6 +21,7 @@ #include "qt_softwarerenderer.hpp" #include #include +#include extern "C" { #include <86box/86box.h> @@ -31,7 +32,7 @@ SoftwareRenderer::SoftwareRenderer(QWidget *parent) #ifdef __HAIKU__ : QWidget(parent) #else - : QRasterWindow(parent->windowHandle()) + : QWindow(parent->windowHandle()), m_backingStore(new QBackingStore(this)) #endif { RendererCommon::parentWidget = parent; @@ -47,12 +48,36 @@ SoftwareRenderer::SoftwareRenderer(QWidget *parent) #endif } +#ifdef __HAIKU__ void SoftwareRenderer::paintEvent(QPaintEvent *event) { (void) event; onPaint(this); } +#endif + +void +SoftwareRenderer::render() +{ + if (!isExposed()) + return; + + QRect rect(0, 0, width(), height()); + m_backingStore->beginPaint(rect); + + QPaintDevice *device = m_backingStore->paintDevice(); + onPaint(device); + + m_backingStore->endPaint(); + m_backingStore->flush(rect); +} + +void +SoftwareRenderer::exposeEvent(QExposeEvent* event) +{ + render(); +} void SoftwareRenderer::onBlit(int buf_idx, int x, int y, int w, int h) @@ -70,7 +95,11 @@ SoftwareRenderer::onBlit(int buf_idx, int x, int y, int w, int h) if (source != origSource) onResize(this->width(), this->height()); +#ifdef __HAIKU__ update(); +#else + render(); +#endif } void @@ -80,7 +109,9 @@ SoftwareRenderer::resizeEvent(QResizeEvent *event) #ifdef __HAIKU__ QWidget::resizeEvent(event); #else - QRasterWindow::resizeEvent(event); + QWindow::resizeEvent(event); + m_backingStore->resize(event->size()); + render(); #endif } @@ -92,7 +123,7 @@ SoftwareRenderer::event(QEvent *event) #ifdef __HAIKU__ return QWidget::event(event); #else - return QRasterWindow::event(event); + return QWindow::event(event); #endif return res; } @@ -112,6 +143,9 @@ SoftwareRenderer::onPaint(QPaintDevice *device) #endif painter.setCompositionMode(QPainter::CompositionMode_Plus); painter.drawImage(destination, *images[cur_image], source); +#ifndef __HAIKU__ + painter.end(); +#endif } std::vector> diff --git a/src/qt/qt_softwarerenderer.hpp b/src/qt/qt_softwarerenderer.hpp index ec64f7000..c9c2706cd 100644 --- a/src/qt/qt_softwarerenderer.hpp +++ b/src/qt/qt_softwarerenderer.hpp @@ -2,8 +2,10 @@ #define SOFTWARERENDERER_HPP #include -#include +#include #include +#include +#include #include #include #include "qt_renderercommon.hpp" @@ -12,14 +14,18 @@ class SoftwareRenderer : #ifdef __HAIKU__ public QWidget, #else - public QRasterWindow, + public QWindow, #endif public RendererCommon { Q_OBJECT public: explicit SoftwareRenderer(QWidget *parent = nullptr); +#ifdef __HAIKU__ void paintEvent(QPaintEvent *event) override; +#endif + + void exposeEvent(QExposeEvent* event) override; std::vector> getBuffers() override; @@ -33,6 +39,10 @@ protected: void onPaint(QPaintDevice *device); void resizeEvent(QResizeEvent *event) override; bool event(QEvent *event) override; + + void render(); + + QScopedPointer m_backingStore; }; #endif // SOFTWARERENDERER_HPP diff --git a/src/scsi/scsi.c b/src/scsi/scsi.c index a02f4e7a5..36e1d0638 100644 --- a/src/scsi/scsi.c +++ b/src/scsi/scsi.c @@ -8,8 +8,6 @@ * * Handling of the SCSI controllers. * - * - * * Authors: Miran Grca, * Fred N. van Kempen, * TheCollector1995, diff --git a/src/scsi/scsi_aha154x.c b/src/scsi/scsi_aha154x.c index 7161a53bb..61228b3c0 100644 --- a/src/scsi/scsi_aha154x.c +++ b/src/scsi/scsi_aha154x.c @@ -10,8 +10,6 @@ * made by Adaptec, Inc. These controllers were designed for * the ISA bus. * - * - * * Authors: Fred N. van Kempen, * Original Buslogic version by SA1988 and Miran Grca. * diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index c2ecc7b62..daeb0a3e4 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -11,8 +11,6 @@ * 1 - BT-545S ISA; * 2 - BT-958D PCI * - * - * * Authors: TheCollector1995, * Miran Grca, * Fred N. van Kempen, diff --git a/src/scsi/scsi_device.c b/src/scsi/scsi_device.c index 33d3fa89a..1f6967105 100644 --- a/src/scsi/scsi_device.c +++ b/src/scsi/scsi_device.c @@ -8,8 +8,6 @@ * * The generic SCSI device command handler. * - * - * * Authors: Miran Grca, * Fred N. van Kempen, * diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index 9c8d36f7f..6c59ee7ad 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -6,8 +6,6 @@ * * Emulation of SCSI fixed disks. * - * - * * Authors: Miran Grca, * * Copyright 2017-2018 Miran Grca. diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index 132fade37..102e637c4 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -9,8 +9,6 @@ * Implementation of the NCR 5380 chip made by NCR * and used in various controllers. * - * - * * Authors: Sarah Walker, * TheCollector1995, * Fred N. van Kempen, diff --git a/src/scsi/scsi_ncr53c400.c b/src/scsi/scsi_ncr53c400.c index 5f2302b4f..31a2de8b3 100644 --- a/src/scsi/scsi_ncr53c400.c +++ b/src/scsi/scsi_ncr53c400.c @@ -9,8 +9,6 @@ * Implementation of the NCR 53c400 series of SCSI Host Adapters * made by NCR. These controllers were designed for the ISA and MCA bus. * - * - * * Authors: Sarah Walker, * TheCollector1995, * Fred N. van Kempen, diff --git a/src/scsi/scsi_ncr53c8xx.c b/src/scsi/scsi_ncr53c8xx.c index f87f22452..bc3ecec0b 100644 --- a/src/scsi/scsi_ncr53c8xx.c +++ b/src/scsi/scsi_ncr53c8xx.c @@ -10,8 +10,6 @@ * Adapters made by NCR and later Symbios and LSI. These * controllers were designed for the PCI bus. * - * - * * Authors: Paul Brook (QEMU) * Artyom Tarasenko (QEMU) * TheCollector1995, diff --git a/src/scsi/scsi_pcscsi.c b/src/scsi/scsi_pcscsi.c index 2c73066a1..11793f5a9 100644 --- a/src/scsi/scsi_pcscsi.c +++ b/src/scsi/scsi_pcscsi.c @@ -9,8 +9,6 @@ * Implementation of the Tekram DC-390 SCSI and related MCA * controllers using the NCR 53c9x series of chips. * - * - * * Authors: Fabrice Bellard (QEMU) * Herve Poussineau (QEMU) * TheCollector1995, diff --git a/src/scsi/scsi_spock.c b/src/scsi/scsi_spock.c index 0bb2d70ba..cf0236236 100644 --- a/src/scsi/scsi_spock.c +++ b/src/scsi/scsi_spock.c @@ -9,8 +9,6 @@ * Implementation of the IBM PS/2 SCSI controller with * cache for MCA only. * - * - * * Authors: Sarah Walker, * TheCollector1995, * diff --git a/src/scsi/scsi_t128.c b/src/scsi/scsi_t128.c index e2f963900..5b893dd70 100644 --- a/src/scsi/scsi_t128.c +++ b/src/scsi/scsi_t128.c @@ -9,8 +9,6 @@ * Implementation of the Trantor 128/228 series of SCSI Host Adapters * made by Trantor. These controllers were designed for the ISA and MCA bus. * - * - * * Authors: Sarah Walker, * TheCollector1995, * Fred N. van Kempen, diff --git a/src/scsi/scsi_x54x.c b/src/scsi/scsi_x54x.c index c248fbe92..b4256f94d 100644 --- a/src/scsi/scsi_x54x.c +++ b/src/scsi/scsi_x54x.c @@ -11,8 +11,6 @@ * series of SCSI Host Adapters made by Mylex. * These controllers were designed for various buses. * - * - * * Authors: TheCollector1995, * Miran Grca, * Fred N. van Kempen, diff --git a/src/sio/sio_82091aa.c b/src/sio/sio_82091aa.c index cfe33df12..6a38ec92c 100644 --- a/src/sio/sio_82091aa.c +++ b/src/sio/sio_82091aa.c @@ -8,8 +8,6 @@ * * Emulation of the Intel 82091AA Super I/O chip. * - * - * * Authors: Miran Grca, * * Copyright 2020 Miran Grca. diff --git a/src/sio/sio_acc3221.c b/src/sio/sio_acc3221.c index c9cb8b6cf..babcff121 100644 --- a/src/sio/sio_acc3221.c +++ b/src/sio/sio_acc3221.c @@ -8,8 +8,6 @@ * * Implementation of the ACC 3221-SP Super I/O Chip. * - * - * * Authors: Sarah Walker, * * Copyright 2019 Sarah Walker. diff --git a/src/sio/sio_ali5123.c b/src/sio/sio_ali5123.c index 5dad42252..39d6f1b90 100644 --- a/src/sio/sio_ali5123.c +++ b/src/sio/sio_ali5123.c @@ -8,8 +8,6 @@ * * Implementation of the ALi M5123/1543C Super I/O Chip. * - * - * * Authors: Miran Grca, * * Copyright 2016-2018 Miran Grca. diff --git a/src/sio/sio_cbm_io.c b/src/sio/sio_cbm_io.c index 477c30a44..2bcdadd65 100644 --- a/src/sio/sio_cbm_io.c +++ b/src/sio/sio_cbm_io.c @@ -8,8 +8,6 @@ * * Implementation of the ACC 3221-SP Super I/O Chip. * - * - * * Authors: Sarah Walker, * * Copyright 2019 Sarah Walker. diff --git a/src/sio/sio_detect.c b/src/sio/sio_detect.c index d36522fe0..d34718db9 100644 --- a/src/sio/sio_detect.c +++ b/src/sio/sio_detect.c @@ -8,8 +8,6 @@ * * Super I/O chip detection code. * - * - * * Authors: Miran Grca, * * Copyright 2016-2018 Miran Grca. diff --git a/src/sio/sio_f82c710.c b/src/sio/sio_f82c710.c index f7ff1409f..46cb61a40 100644 --- a/src/sio/sio_f82c710.c +++ b/src/sio/sio_f82c710.c @@ -349,7 +349,7 @@ f82c710_init(const device_t *info) { upc_t *dev = (upc_t *) calloc(1, sizeof(upc_t)); - if (strstr(machine_get_internal_name(), "5086") != NULL) + if (machines[machine].init == machine_xt_pc5086_init) dev->fdc = device_add(&fdc_at_actlow_device); else dev->fdc = device_add(&fdc_at_device); diff --git a/src/sio/sio_fdc37c669.c b/src/sio/sio_fdc37c669.c index 57ca37619..122afc521 100644 --- a/src/sio/sio_fdc37c669.c +++ b/src/sio/sio_fdc37c669.c @@ -8,8 +8,6 @@ * * Implementation of the SMC FDC37C669 Super I/O Chip. * - * - * * Authors: Miran Grca, * * Copyright 2016-2024 Miran Grca. diff --git a/src/sio/sio_fdc37c93x.c b/src/sio/sio_fdc37c93x.c index 47e73ebae..399469424 100644 --- a/src/sio/sio_fdc37c93x.c +++ b/src/sio/sio_fdc37c93x.c @@ -143,7 +143,7 @@ static __inline uint8_t fdc37c93x_do_read_gp(fdc37c93x_t *dev, int reg, int bit) { /* Update bit 2 on the Acer V35N according to the selected graphics card type. */ - if ((reg == 2) && (strstr(machine_get_internal_name(), "acer") != NULL)) + if ((reg == 2) && !strncmp(machine_get_internal_name(), "acer", 4)) dev->gpio_pulldn[reg] = (dev->gpio_pulldn[reg] & 0xfb) | (video_is_mda() ? 0x00 : 0x04); return dev->gpio_regs[reg] & dev->gpio_pulldn[reg] & (1 << bit); @@ -1812,7 +1812,7 @@ fdc37c93x_reset(void *priv) memset(dev->gpio_pulldn, 0xff, 8); /* Acer V62X requires bit 0 to be clear to not be stuck in "clear password" mode. */ - if (!strcmp(machine_get_internal_name(), "vectra54")) { + if (machines[machine].init == machine_at_vectra54_init) { dev->gpio_pulldn[1] = 0x40; /* @@ -1850,12 +1850,12 @@ fdc37c93x_reset(void *priv) dev->gpio_pulldn[1] |= 0x00; else if (cpu_dmulti > 2.5) dev->gpio_pulldn[1] |= 0x80; - } else if (!strcmp(machine_get_internal_name(), "acerv62x")) + } else if (machines[machine].init == machine_at_acerv62x_init) dev->gpio_pulldn[1] = 0xfe; else dev->gpio_pulldn[1] = (dev->chip_id == 0x30) ? 0xff : 0xfd; - if (strstr(machine_get_internal_name(), "acer") != NULL) + if (!strncmp(machine_get_internal_name(), "acer", 4)) /* Bit 2 on the Acer V35N is the text/graphics toggle, bits 1 and 3 = ????. */ dev->gpio_pulldn[2] = 0x10; diff --git a/src/sio/sio_it86x1f.c b/src/sio/sio_it86x1f.c index 324914355..77011de26 100644 --- a/src/sio/sio_it86x1f.c +++ b/src/sio/sio_it86x1f.c @@ -8,8 +8,6 @@ * * Emulation of the ITE IT86x1F Super I/O chips. * - * - * * Authors: RichardG, * * Copyright 2023 RichardG. @@ -43,7 +41,7 @@ enum { ITE_IT8671F = 0x8681 }; -#define CHIP_ID *((uint16_t *) &dev->global_regs[0]) +#define CHIP_ID AS_U16(dev->global_regs[0]) static void it8671f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv); static void it8661f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv); @@ -571,7 +569,7 @@ it86x1f_pnp_write_vendor_reg(uint8_t ld, uint8_t reg, uint8_t val, void *priv) case 0x7e3: if ((CHIP_ID == ITE_IT8671F) && (val & 0x80)) - *((uint16_t *) &dev->gpio_regs[0x22]) = 0x0000; + AS_U16(dev->gpio_regs[0x22]) = 0x0000; break; case 0x7fb: diff --git a/src/sio/sio_pc87306.c b/src/sio/sio_pc87306.c index f3c635dc8..f9e066b1f 100644 --- a/src/sio/sio_pc87306.c +++ b/src/sio/sio_pc87306.c @@ -8,8 +8,6 @@ * * Emulation of the NatSemi PC87306 Super I/O chip. * - * - * * Authors: Miran Grca, * * Copyright 2016-2018 Miran Grca. diff --git a/src/sio/sio_um8669f.c b/src/sio/sio_um8669f.c index 96c37573d..3431ae63e 100644 --- a/src/sio/sio_um8669f.c +++ b/src/sio/sio_um8669f.c @@ -44,7 +44,6 @@ 10 ASKIR 11 Disabled */ - #include #include #include diff --git a/src/sio/sio_vl82c113.c b/src/sio/sio_vl82c113.c index bf63e9023..b5ecde3c9 100644 --- a/src/sio/sio_vl82c113.c +++ b/src/sio/sio_vl82c113.c @@ -134,7 +134,7 @@ vl82c113_init(UNUSED(const device_t *info)) { vl82c113_t *dev = (vl82c113_t *) calloc(1, sizeof(vl82c113_t)); - if (!strcmp(machine_get_internal_name(), "martin")) + if (machines[machine].init == machine_at_martin_init) dev->nvr = device_add(&martin_nvr_device); else dev->nvr = device_add(&amstrad_megapc_nvr_device); diff --git a/src/sio/sio_vt82c686.c b/src/sio/sio_vt82c686.c index 4caffbc00..4b6228905 100644 --- a/src/sio/sio_vt82c686.c +++ b/src/sio/sio_vt82c686.c @@ -8,8 +8,6 @@ * * Emulation of the VIA VT82C686A/B integrated Super I/O. * - * - * * Authors: RichardG, * * Copyright 2020 RichardG. diff --git a/src/sio/sio_w837x7.c b/src/sio/sio_w837x7.c index 0b6aae240..ecf51d061 100644 --- a/src/sio/sio_w837x7.c +++ b/src/sio/sio_w837x7.c @@ -9,6 +9,7 @@ * Emulation of the Winbond W837x7F/IF Super I/O Chip. * * Authors: Miran Grca, + * * Copyright 2020-2025 Miran Grca. */ #include diff --git a/src/sio/sio_w83877.c b/src/sio/sio_w83877.c index a7a2b4ea2..b57ad76ff 100644 --- a/src/sio/sio_w83877.c +++ b/src/sio/sio_w83877.c @@ -9,6 +9,7 @@ * Emulation of the Winbond W83877 family of Super I/O Chips. * * Authors: Miran Grca, + * * Copyright 2016-2025 Miran Grca. */ #include @@ -527,7 +528,7 @@ w83877_init(const device_t *info) dev->has_ide = (info->local >> 16) & 0xff; - if (!strcmp(machine_get_internal_name(), "ficpa2012")) { + if (machines[machine].init == machine_at_ficpa2012_init) { dev->dma_map[0] = 4; dev->dma_map[1] = 3; dev->dma_map[2] = 1; diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index fdc60b971..ccb54ab19 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -52,6 +52,7 @@ add_library(snd OBJECT snd_optimc.c snd_opl_esfm.c snd_ymf701.c + snd_ymf71x.c ) # TODO: Should platform-specific audio driver be here? diff --git a/src/sound/audio4.c b/src/sound/audio4.c index c8fca5994..060e574e6 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -1,17 +1,16 @@ /* - * 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. * - * Interface to audio(4) for NetBSD/OpenBSD. + * Interface to audio(4) for NetBSD/OpenBSD. * + * Authors: Nishi * - * Authors: Nishi - * - * Copyright 2025 Nishi. + * Copyright 2025 Nishi. */ #include #include diff --git a/src/sound/midi.c b/src/sound/midi.c index 9f83e88dc..f64ba64ff 100644 --- a/src/sound/midi.c +++ b/src/sound/midi.c @@ -1,22 +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. + * 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. * - * MIDI device core module. + * MIDI device core module. * + * Authors: Miran Grca, + * Bit, + * DOSBox Team, * - * - * Authors: Miran Grca, - * Bit, - * DOSBox Team, - * - * Copyright 2016-2020 Miran Grca. - * Copyright 2016-2020 Bit. - * Copyright 2008-2020 DOSBox Team. + * Copyright 2016-2020 Miran Grca. + * Copyright 2016-2020 Bit. + * Copyright 2008-2020 DOSBox Team. */ #include #include @@ -29,6 +27,9 @@ #include <86box/midi.h> #include <86box/plat.h> +#define MIDI_SYSEX_MAX_ITERATIONS 1000 +#define MIDI_SYSEX_TIMEOUT_MS 5000 + int midi_output_device_current = 0; static int midi_output_device_last = 0; int midi_input_device_current = 0; @@ -570,15 +571,44 @@ midi_do_sysex(void) void midi_in_sysex(uint8_t *buffer, uint32_t len) { + int max_iterations = MIDI_SYSEX_MAX_ITERATIONS; + int iteration_count = 0; + uint32_t start_time = plat_get_ticks(); + uint32_t max_timeout_ms = MIDI_SYSEX_TIMEOUT_MS; + + /* Input validation */ + if (!buffer || len == 0) { + return; + } + midi_start_sysex(buffer, len); - while (1) { - /* This will return 0 if all theh handlers have either - timed out or otherwise indicated it is time to stop. */ - if (midi_do_sysex()) - plat_delay_ms(5); /* msec */ - else + while (iteration_count < max_iterations) { + /* Check for timeout */ + uint32_t elapsed_time = plat_get_ticks() - start_time; + if (elapsed_time > max_timeout_ms) { + /* Force abort all handlers on timeout */ + midi_in_handler_t *temp = mih_first; + while (temp != NULL) { + if (temp->sysex) { + temp->sysex(temp->priv, NULL, 0, 1); /* Call with abort=1 */ + } + temp->cnt = 0; + temp->len = 0; + temp = temp->next; + } + /* pclog("MIDI: SYSEX processing timed out after %d ms\n", elapsed_time); */ break; + } + + /* This will return 0 if all the handlers have either + timed out or otherwise indicated it is time to stop. */ + if (midi_do_sysex()) { + plat_delay_ms(5); /* msec */ + iteration_count++; + } else { + break; + } } } diff --git a/src/sound/midi_rtmidi.cpp b/src/sound/midi_rtmidi.cpp index 11203c3f2..e5e03bc0d 100644 --- a/src/sound/midi_rtmidi.cpp +++ b/src/sound/midi_rtmidi.cpp @@ -10,10 +10,10 @@ * * Author: Cacodemon345, * Miran Grca, + * * Copyright 2021 Cacodemon345. * Copyright 2021 Miran Grca. */ - #if defined __has_include # if __has_include() # include diff --git a/src/sound/openal.c b/src/sound/openal.c index 4bd2d6c5d..d163150af 100644 --- a/src/sound/openal.c +++ b/src/sound/openal.c @@ -1,20 +1,18 @@ /* - * 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. * - * Interface to the OpenAL sound processing library. + * Interface to the OpenAL sound processing library. * + * Authors: Sarah Walker, + * Miran Grca, * - * - * Authors: Sarah Walker, - * Miran Grca, - * - * Copyright 2008-2019 Sarah Walker. - * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include diff --git a/src/sound/snd_ac97_codec.c b/src/sound/snd_ac97_codec.c index 1b28a8aab..77e5825d9 100644 --- a/src/sound/snd_ac97_codec.c +++ b/src/sound/snd_ac97_codec.c @@ -1,18 +1,16 @@ /* - * 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. * - * AC'97 audio codec emulation. + * AC'97 audio codec emulation. * + * Authors: RichardG, * - * - * Authors: RichardG, - * - * Copyright 2021 RichardG. + * Copyright 2021 RichardG. */ #include #include diff --git a/src/sound/snd_ac97_via.c b/src/sound/snd_ac97_via.c index 2d994b08f..28b802a6f 100644 --- a/src/sound/snd_ac97_via.c +++ b/src/sound/snd_ac97_via.c @@ -1,18 +1,16 @@ /* - * 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. * - * VIA AC'97 audio controller emulation. + * VIA AC'97 audio controller emulation. * + * Authors: RichardG, * - * - * Authors: RichardG, - * - * Copyright 2021 RichardG. + * Copyright 2021 RichardG. */ #include #include @@ -348,7 +346,7 @@ ac97_via_sgd_write(uint16_t addr, uint8_t val, void *priv) dev->sgd_regs[modem][addr & 0xf0] = (dev->sgd_regs[modem][addr & 0xf0] & ~0x47) | 0x80; /* Start at the specified entry pointer. */ - dev->sgd[modem][addr >> 4].entry_ptr = *((uint32_t *) &dev->sgd_regs[modem][(addr & 0xf0) | 0x4]) & 0xfffffffe; + dev->sgd[modem][addr >> 4].entry_ptr = AS_U32(dev->sgd_regs[modem][(addr & 0xf0) | 0x4]) & 0xfffffffe; dev->sgd[modem][addr >> 4].restart = 2; /* Start the actual SGD process. */ @@ -403,14 +401,14 @@ ac97_via_sgd_write(uint16_t addr, uint8_t val, void *priv) if (val & 1) { /* return 0x0000 on unaligned reads (real 686B behavior) */ dev->sgd_regs[modem][0x80] = dev->sgd_regs[modem][0x81] = 0x00; } else { - *((uint16_t *) &dev->codec_shadow[modem].regs_codec[i][val & 0x7f]) = *((uint16_t *) &dev->sgd_regs[modem][0x80]) = ac97_codec_readw(codec, val); + AS_U16(dev->codec_shadow[modem].regs_codec[i][val & 0x7f]) = AS_U16(dev->sgd_regs[modem][0x80]) = ac97_codec_readw(codec, val); } /* Flag data/status/index for this codec as valid. */ dev->sgd_regs[modem][0x83] |= 0x02 << (i << 1); } else if (!(val & 1)) { /* do nothing on unaligned writes */ ac97_codec_writew(codec, val, - *((uint16_t *) &dev->codec_shadow[modem].regs_codec[i][val & 0x7f]) = *((uint16_t *) &dev->sgd_regs[modem][0x80])); + AS_U16(dev->codec_shadow[modem].regs_codec[i][val & 0x7f]) = AS_U16(dev->sgd_regs[modem][0x80])); /* Update primary audio codec state if that codec was written to. */ if (!modem && !i) { @@ -579,7 +577,7 @@ ac97_via_sgd_process(void *priv) if (sgd->restart) { /* (Re)load entry pointer if required. */ if (sgd->restart & 2) - sgd->entry_ptr = *((uint32_t *) &dev->sgd_regs[sgd->modem][sgd->id | 0x4]) & 0xfffffffe; /* TODO: probe real hardware - does "even addr" actually mean dword aligned? */ + sgd->entry_ptr = AS_U32(dev->sgd_regs[sgd->modem][sgd->id | 0x4]) & 0xfffffffe; /* TODO: probe real hardware - does "even addr" actually mean dword aligned? */ sgd->restart = 0; /* Read entry. */ @@ -605,11 +603,11 @@ ac97_via_sgd_process(void *priv) if (sgd->id & 0x10) { /* Write channel: read data from FIFO. */ - // mem_writel_phys(sgd->sample_ptr, *((uint32_t *) &sgd->fifo[sgd->fifo_end & (sizeof(sgd->fifo) - 1)])); + // mem_writel_phys(sgd->sample_ptr, AS_U32(sgd->fifo[sgd->fifo_end & (sizeof(sgd->fifo) - 1)])); dma_bm_write(sgd->sample_ptr, &sgd->fifo[sgd->fifo_end & (sizeof(sgd->fifo) - 1)], 4, 4); } else { /* Read channel: write data to FIFO. */ - // *((uint32_t *) &sgd->fifo[sgd->fifo_end & (sizeof(sgd->fifo) - 1)]) = mem_readl_phys(sgd->sample_ptr); + // AS_U32(sgd->fifo[sgd->fifo_end & (sizeof(sgd->fifo) - 1)]) = mem_readl_phys(sgd->sample_ptr); dma_bm_read(sgd->sample_ptr, &sgd->fifo[sgd->fifo_end & (sizeof(sgd->fifo) - 1)], 4, 4); } sgd->fifo_end += 4; @@ -709,7 +707,7 @@ ac97_via_poll_stereo(void *priv) case 0x20: /* Mono, 16-bit PCM */ if ((sgd->fifo_end - sgd->fifo_pos) >= 2) { - sgd->out_l = sgd->out_r = *((uint16_t *) &sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]); + sgd->out_l = sgd->out_r = AS_U16(sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]); sgd->fifo_pos += 2; return; } @@ -717,9 +715,9 @@ ac97_via_poll_stereo(void *priv) case 0x30: /* Stereo, 16-bit PCM */ if ((sgd->fifo_end - sgd->fifo_pos) >= 4) { - sgd->out_l = *((uint16_t *) &sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]); + sgd->out_l = AS_U16(sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]); sgd->fifo_pos += 2; - sgd->out_r = *((uint16_t *) &sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]); + sgd->out_r = AS_U16(sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]); sgd->fifo_pos += 2; return; } @@ -749,9 +747,9 @@ ac97_via_poll_fm(void *priv) /* Feed next sample from the FIFO. The data format is not documented, but it probes as 16-bit stereo at 24 KHz. */ if ((sgd->fifo_end - sgd->fifo_pos) >= 4) { - sgd->out_l = *((uint16_t *) &sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]); + sgd->out_l = AS_U16(sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]); sgd->fifo_pos += 2; - sgd->out_r = *((uint16_t *) &sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]); + sgd->out_r = AS_U16(sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]); sgd->fifo_pos += 2; return; } diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index ff9d36318..94520070e 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -1,22 +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. + * 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. * - * AD1848 / CS4248 / CS4231 (Windows Sound System) codec emulation. + * AD1848 / CS4248 / CS4231 (Windows Sound System) codec emulation. * + * Authors: Sarah Walker, + * TheCollector1995, + * RichardG, * - * - * Authors: Sarah Walker, - * TheCollector1995, - * RichardG, - * - * Copyright 2008-2020 Sarah Walker. - * Copyright 2018-2020 TheCollector1995. - * Copyright 2021-2025 RichardG. + * Copyright 2008-2020 Sarah Walker. + * Copyright 2018-2020 TheCollector1995. + * Copyright 2021-2025 RichardG. */ #include #include @@ -488,6 +486,8 @@ readonly_x: ad1848_log("AD1848: write(X%d, %02X)\n", ad1848->xindex, val); return; } + if (ad1848->type == AD1848_TYPE_CS4231) /* I23 is reserved and read-only on CS4231 non-A */ + goto readonly_i; break; case 24: diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index 1ca547650..23c4863c7 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -438,8 +438,8 @@ es137x_reset(void *priv) /* Default subsystem ID. */ dev->subsys_lock = 0x00; - *((uint16_t *) &dev->subsys_id[0]) = (dev->type == AUDIOPCI_ES1370) ? 0x4942 : 0x1274; - *((uint16_t *) &dev->subsys_id[2]) = (dev->type == AUDIOPCI_ES1370) ? 0x4c4c : 0x1371; + AS_U16(dev->subsys_id[0]) = (dev->type == AUDIOPCI_ES1370) ? 0x4942 : 0x1274; + AS_U16(dev->subsys_id[2]) = (dev->type == AUDIOPCI_ES1370) ? 0x4c4c : 0x1371; /* Interrupt/Chip Select Control Register, Address 00H Addressable as byte, word, longword */ diff --git a/src/sound/snd_cmi8x38.c b/src/sound/snd_cmi8x38.c index a41f53865..9ee003689 100644 --- a/src/sound/snd_cmi8x38.c +++ b/src/sound/snd_cmi8x38.c @@ -8,8 +8,6 @@ * * C-Media CMI8x38 PCI audio controller emulation. * - * - * * Authors: RichardG, * * Copyright 2022 RichardG. @@ -147,7 +145,7 @@ static void cmi8x38_update_irqs(cmi8x38_t *dev) { /* Calculate and use the INTR flag. */ - if (*((uint32_t *) &dev->io_regs[0x10]) & 0x0401c003) { + if (AS_U32(dev->io_regs[0x10]) & 0x0401c003) { dev->io_regs[0x13] |= 0x80; pci_set_irq(dev->pci_slot, PCI_INTA, &dev->irq_state); cmi8x38_log("CMI8x38: Raising IRQ\n"); @@ -912,19 +910,19 @@ cmi8x38_write(uint16_t addr, uint8_t val, void *priv) case 0x80 ... 0x83: case 0x88 ... 0x8b: dev->io_regs[addr] = val; - dev->dma[(addr & 0x78) >> 3].sample_ptr = *((uint32_t *) &dev->io_regs[addr & 0xfc]); + dev->dma[(addr & 0x78) >> 3].sample_ptr = AS_U32(dev->io_regs[addr & 0xfc]); return; case 0x84 ... 0x85: case 0x8c ... 0x8d: dev->io_regs[addr] = val; - dev->dma[(addr & 0x78) >> 3].frame_count_dma = dev->dma[(addr & 0x78) >> 3].sample_count_out = *((uint16_t *) &dev->io_regs[addr & 0xfe]) + 1; + dev->dma[(addr & 0x78) >> 3].frame_count_dma = dev->dma[(addr & 0x78) >> 3].sample_count_out = AS_U16(dev->io_regs[addr & 0xfe]) + 1; return; case 0x86 ... 0x87: case 0x8e ... 0x8f: dev->io_regs[addr] = val; - dev->dma[(addr & 0x78) >> 3].frame_count_fragment = *((uint16_t *) &dev->io_regs[addr & 0xfe]) + 1; + dev->dma[(addr & 0x78) >> 3].frame_count_fragment = AS_U16(dev->io_regs[addr & 0xfe]) + 1; return; case 0x92: @@ -1074,19 +1072,19 @@ cmi8x38_dma_process(void *priv) /* Set up base address and counters. Nothing reads sample_count_out; it's implemented as an assumption. */ dma->restart = 0; - dma->sample_ptr = *((uint32_t *) &dev->io_regs[dma->reg]); - dma->frame_count_dma = dma->sample_count_out = *((uint16_t *) &dev->io_regs[dma->reg | 0x4]) + 1; - dma->frame_count_fragment = *((uint16_t *) &dev->io_regs[dma->reg | 0x6]) + 1; + dma->sample_ptr = AS_U32(dev->io_regs[dma->reg]); + dma->frame_count_dma = dma->sample_count_out = AS_U16(dev->io_regs[dma->reg | 0x4]) + 1; + dma->frame_count_fragment = AS_U16(dev->io_regs[dma->reg | 0x6]) + 1; cmi8x38_log("CMI8x38: Starting DMA %d at %08X (count %04X fragment %04X)\n", dma->id, dma->sample_ptr, dma->frame_count_dma, dma->frame_count_fragment); } if (dma_status & 0x01) { /* Write channel: read data from FIFO. */ - mem_writel_phys(dma->sample_ptr, *((uint32_t *) &dma->fifo[dma->fifo_end & (sizeof(dma->fifo) - 1)])); + mem_writel_phys(dma->sample_ptr, AS_U32(dma->fifo[dma->fifo_end & (sizeof(dma->fifo) - 1)])); } else { /* Read channel: write data to FIFO. */ - *((uint32_t *) &dma->fifo[dma->fifo_end & (sizeof(dma->fifo) - 1)]) = mem_readl_phys(dma->sample_ptr); + AS_U32(dma->fifo[dma->fifo_end & (sizeof(dma->fifo) - 1)]) = mem_readl_phys(dma->sample_ptr); } dma->fifo_end += 4; dma->sample_ptr += 4; @@ -1094,7 +1092,7 @@ cmi8x38_dma_process(void *priv) /* Check if the fragment size was reached. */ if (--dma->frame_count_fragment <= 0) { /* Reset fragment counter. */ - dma->frame_count_fragment = *((uint16_t *) &dev->io_regs[dma->reg | 0x6]) + 1; + dma->frame_count_fragment = AS_U16(dev->io_regs[dma->reg | 0x6]) + 1; #ifdef ENABLE_CMI8X38_LOG if (dma->frame_count_fragment > 1) /* avoid log spam if fragment counting is unused, like on the newer WDM drivers (cmudax3) */ cmi8x38_log("CMI8x38: DMA %d fragment size reached at %04X frames left", dma->id, dma->frame_count_dma - 1); @@ -1181,7 +1179,7 @@ cmi8x38_poll(void *priv) case 0x02: /* Mono, 16-bit PCM */ if ((dma->fifo_end - dma->fifo_pos) >= 2) { - *out_l = *out_r = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + *out_l = *out_r = AS_U16(dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); dma->fifo_pos += 2; dma->sample_count_out -= 2; goto n4spk3d; @@ -1192,9 +1190,9 @@ cmi8x38_poll(void *priv) switch (dma->channels) { case 2: if ((dma->fifo_end - dma->fifo_pos) >= 4) { - *out_l = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + *out_l = AS_U16(dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); dma->fifo_pos += 2; - *out_r = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + *out_r = AS_U16(dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); dma->fifo_pos += 2; dma->sample_count_out -= 4; goto n4spk3d; @@ -1203,13 +1201,13 @@ cmi8x38_poll(void *priv) case 4: if ((dma->fifo_end - dma->fifo_pos) >= 8) { - dma->out_fl = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->out_fl = AS_U16(dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); dma->fifo_pos += 2; - dma->out_fr = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->out_fr = AS_U16(dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); dma->fifo_pos += 2; - dma->out_rl = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->out_rl = AS_U16(dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); dma->fifo_pos += 2; - dma->out_rr = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->out_rr = AS_U16(dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); dma->fifo_pos += 2; dma->sample_count_out -= 8; return; @@ -1218,15 +1216,15 @@ cmi8x38_poll(void *priv) case 5: /* not supported by WDM and Linux drivers; channel layout assumed */ if ((dma->fifo_end - dma->fifo_pos) >= 10) { - dma->out_fl = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->out_fl = AS_U16(dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); dma->fifo_pos += 2; - dma->out_fr = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->out_fr = AS_U16(dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); dma->fifo_pos += 2; - dma->out_rl = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->out_rl = AS_U16(dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); dma->fifo_pos += 2; - dma->out_rr = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->out_rr = AS_U16(dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); dma->fifo_pos += 2; - dma->out_c = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->out_c = AS_U16(dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); dma->fifo_pos += 2; dma->sample_count_out -= 10; return; @@ -1235,17 +1233,17 @@ cmi8x38_poll(void *priv) case 6: if ((dma->fifo_end - dma->fifo_pos) >= 12) { - dma->out_fl = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->out_fl = AS_U16(dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); dma->fifo_pos += 2; - dma->out_fr = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->out_fr = AS_U16(dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); dma->fifo_pos += 2; - dma->out_rl = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->out_rl = AS_U16(dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); dma->fifo_pos += 2; - dma->out_rr = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->out_rr = AS_U16(dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); dma->fifo_pos += 2; - dma->out_c = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->out_c = AS_U16(dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); dma->fifo_pos += 2; - dma->out_lfe = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->out_lfe = AS_U16(dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); dma->fifo_pos += 2; dma->sample_count_out -= 12; return; @@ -1265,7 +1263,7 @@ cmi8x38_poll(void *priv) *out_l = *out_r = 0; /* Stop playback if DMA is disabled. */ - if ((*((uint32_t *) &dev->io_regs[0x00]) & (0x00010001 << dma->id)) != (0x00010000 << dma->id)) { + if ((AS_U32(dev->io_regs[0x00]) & (0x00010001 << dma->id)) != (0x00010000 << dma->id)) { cmi8x38_log("CMI8x38: Stopping playback of DMA channel %d\n", dma->id); dma->playback_enabled = 0; } diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index 5905fb64e..15ad71782 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -1,18 +1,16 @@ /* - * 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. * - * Crystal CS423x (SBPro/WSS compatible sound chips) emulation. + * Crystal CS423x (SBPro/WSS compatible sound chips) emulation. * + * Authors: RichardG, * - * - * Authors: RichardG, - * - * Copyright 2021-2025 RichardG. + * Copyright 2021-2025 RichardG. */ #include #include diff --git a/src/sound/snd_mpu401.c b/src/sound/snd_mpu401.c index bec2ed39c..87c191cec 100644 --- a/src/sound/snd_mpu401.c +++ b/src/sound/snd_mpu401.c @@ -1,20 +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. + * 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. * - * Roland MPU-401 emulation. + * Roland MPU-401 emulation. * - * Authors: DOSBox Team, - * Miran Grca, - * TheCollector1995, + * Authors: DOSBox Team, + * Miran Grca, + * TheCollector1995, * - * Copyright 2008-2024 DOSBox Team. - * Copyright 2016-2024 Miran Grca. - * Copyright 2016-2024 TheCollector1995. + * Copyright 2008-2024 DOSBox Team. + * Copyright 2016-2024 Miran Grca. + * Copyright 2016-2024 TheCollector1995. */ #include #include diff --git a/src/sound/snd_opl2board.c b/src/sound/snd_opl2board.c index 632ad85f1..e8d877222 100644 --- a/src/sound/snd_opl2board.c +++ b/src/sound/snd_opl2board.c @@ -7,7 +7,6 @@ * This file is part of the 86Box distribution. * * Interface to the OPL2Board External audio device (USB) - * * * Authors: Jose Phillips * Fred N. van Kempen, @@ -17,7 +16,6 @@ * Copyright 2017-2020 Fred N. van Kempen. * Copyright 2016-2020 Miran Grca. */ - #include #include #include diff --git a/src/sound/snd_opl_esfm.c b/src/sound/snd_opl_esfm.c index b80d264d5..a05f1f52c 100644 --- a/src/sound/snd_opl_esfm.c +++ b/src/sound/snd_opl_esfm.c @@ -8,7 +8,6 @@ * * ESFMu ESFM emulator. * - * * Authors: Fred N. van Kempen, * Miran Grca, * Alexey Khokholov (Nuke.YKT) @@ -19,7 +18,6 @@ * Copyright 2013-2018 Alexey Khokholov (Nuke.YKT) * Copyright 2024 Cacodemon345 */ - #include #include #include diff --git a/src/sound/snd_opl_ymfm.cpp b/src/sound/snd_opl_ymfm.cpp index fb00401d5..815b6cb4b 100644 --- a/src/sound/snd_opl_ymfm.cpp +++ b/src/sound/snd_opl_ymfm.cpp @@ -8,7 +8,6 @@ * * Interface to the YMFM emulator. * - * * Authors: Adrien Moulin, * * Copyright 2022 Adrien Moulin. diff --git a/src/sound/snd_optimc.c b/src/sound/snd_optimc.c index 274bbd568..c6f25aadf 100644 --- a/src/sound/snd_optimc.c +++ b/src/sound/snd_optimc.c @@ -8,15 +8,12 @@ * * OPTi MediaCHIPS 82C929A (also known as OPTi MAD16 Pro) audio controller emulation. * - * - * * Authors: Cacodemon345 * Eluan Costa Miranda * * Copyright 2022 Cacodemon345. * Copyright 2020 Eluan Costa Miranda. */ - #include #include #include diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index 76956c417..80f6c9555 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -515,7 +515,7 @@ sb_dsp_reset(sb_dsp_t *dsp) dsp->sb_command = 0; dsp->sb_8_length = 0xffff; - dsp->sb_8_autolen = 0xffff; + dsp->sb_8_autolen = 0x7fff; dsp->sb_irq8 = 0; dsp->sb_irq16 = 0; diff --git a/src/sound/snd_speaker.c b/src/sound/snd_speaker.c index 063554875..a780861f8 100644 --- a/src/sound/snd_speaker.c +++ b/src/sound/snd_speaker.c @@ -1,20 +1,18 @@ /* - * 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. * - * Emulation of the PC speaker. + * Emulation of the PC speaker. * + * Authors: Sarah Walker, + * Miran Grca, * - * - * Authors: Sarah Walker, - * Miran Grca, - * - * Copyright 2008-2019 Sarah Walker. - * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include diff --git a/src/sound/snd_wss.c b/src/sound/snd_wss.c index 874638a80..aa5166fa6 100644 --- a/src/sound/snd_wss.c +++ b/src/sound/snd_wss.c @@ -1,20 +1,18 @@ /* - * 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. * - * Windows Sound System emulation. + * Windows Sound System emulation. * + * Authors: Sarah Walker, + * TheCollector1995, * - * - * Authors: Sarah Walker, - * TheCollector1995, - * - * Copyright 2012-2018 Sarah Walker. - * Copyright 2018 TheCollector1995. + * Copyright 2012-2018 Sarah Walker. + * Copyright 2018 TheCollector1995. */ #include #include diff --git a/src/sound/snd_ymf701.c b/src/sound/snd_ymf701.c index ff2f9f78a..3b3529320 100644 --- a/src/sound/snd_ymf701.c +++ b/src/sound/snd_ymf701.c @@ -8,8 +8,6 @@ * * Yamaha YMF-701 (OPL3-SA) audio controller emulation. * - * - * * Authors: Cacodemon345 * Eluan Costa Miranda * win2kgamer @@ -18,7 +16,6 @@ * Copyright 2020 Eluan Costa Miranda. * Copyright 2025 win2kgamer */ - #include #include #include diff --git a/src/sound/snd_ymf71x.c b/src/sound/snd_ymf71x.c new file mode 100644 index 000000000..116a0966d --- /dev/null +++ b/src/sound/snd_ymf71x.c @@ -0,0 +1,878 @@ +/* + * 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. + * + * Yamaha YMF-71x (OPL3-SA2/3) audio controller emulation. + * + * Authors: Cacodemon345 + * Eluan Costa Miranda + * win2kgamer + * + * Copyright 2022 Cacodemon345. + * Copyright 2020 Eluan Costa Miranda. + * Copyright 2025 win2kgamer + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H + +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/midi.h> +#include <86box/timer.h> +#include <86box/pic.h> +#include <86box/sound.h> +#include <86box/gameport.h> +#include <86box/snd_ad1848.h> +#include <86box/snd_sb.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/plat_unused.h> +#include <86box/log.h> +#include <86box/i2c.h> +#include <86box/isapnp.h> +#include <86box/nvr.h> +#include <86box/snd_opl.h> +#include <86box/filters.h> +#include "cpu.h" + +#define PNP_ROM_YMF718 "roms/sound/ymf71x/UFC-101.BIN" +#define PNP_ROM_YMF719 "roms/sound/ymf71x/PnP1.BIN" + +#define YMF71X_NO_EEPROM 0x100 + +#ifdef ENABLE_YMF71X_LOG +int ymf71x_do_log = ENABLE_YMF71X_LOG; + +static void +ymf71x_log(void *priv, const char *fmt, ...) +{ + if (ymf71x_do_log) { + va_list ap; + va_start(ap, fmt); + log_out(priv, fmt, ap); + va_end(ap); + } +} +#else +# define ymf71x_log(fmt, ...) +#endif + +static const uint8_t ymf71x_init_key[32] = { 0xB1, 0xD8, 0x6C, 0x36, 0x9B, 0x4D, 0xA6, 0xD3, /* "YAMAHA Key" from the datasheet */ + 0x69, 0xB4, 0x5A, 0xAD, 0xD6, 0xEB, 0x75, 0xBA, + 0xDD, 0xEE, 0xF7, 0x7B, 0x3D, 0x9E, 0xCF, 0x67, + 0x33, 0x19, 0x8C, 0x46, 0xA3, 0x51, 0xA8, 0x54 }; + +/* Reversed attenuation values borrowed from snd_sb.c */ +/* YMF-71x master volume attenuation is -30dB when all bits are 1, 0dB when all bits are 0 */ +static const double ymf71x_att_2dbstep_4bits[] = { + 32767.0, 26027.0, 20674.0, 16422.0, 13044.0, 10362.0, 8230.0, 6537.0, + 5192.0, 4125.0, 3276.0, 2602.0, 2067.0, 1641.0, 1304.0, 164.0 +}; + +/* Taken from the SoundBlaster code, not quite correct but provides the desired effect + without causing distortion when applied to CD audio (at lower settings, highest settings + still do this to CD audio) */ +static const double ymf71x_bass_treble_3bits[] = { + 0, 0.25892541, 0.584893192, 1, 1.511886431, 2.16227766, 3, 4.011872336 +}; + + +typedef struct ymf71x_t { + uint8_t type; + + uint16_t cur_sb_addr; + uint16_t cur_wss_addr; + uint16_t cur_mpu401_addr; + uint16_t cur_opl_addr; + uint16_t cur_ctrl_addr; + + int cur_sb_irq; + int cur_sb_dma; + int cur_wss_enabled; + int cur_wss_irq; + int cur_wss_dma; + int cur_mpu401_irq; + void *gameport; + + ad1848_t ad1848; + mpu_t *mpu; + + sb_t *sb; + uint8_t index; + uint8_t regs[0x20]; + uint8_t max_reg; + double master_l; + double master_r; + + void *pnp_card; + uint8_t pnp_rom[512]; + uint8_t key_pos : 5; + uint8_t configidx; + uint8_t ramwrite_enable; + uint8_t ram_data[512]; + uint16_t ram_addr; + isapnp_device_config_t *ymf71x_pnp_config; + + void * log; /* New logging system */ +} ymf71x_t; + +static void +ymf71x_config_write(uint16_t addr, uint8_t val, void *priv) +{ + ymf71x_t *ymf71x = (ymf71x_t *) priv; + + ymf71x_log(ymf71x->log, "Config Write port = %04X, val = %02X\n", addr, val); + + if (addr == 0x279) { + if (ymf71x->key_pos == 0x00) + ymf71x->key_pos = 0x01; + /* Check for YAMAHA Key */ + if (val == ymf71x_init_key[ymf71x->key_pos]) { + ymf71x->key_pos++; + if (!ymf71x->key_pos) { + ymf71x_log(ymf71x->log, "YMF71x: Config unlocked\n"); + /* Force CSN to 0x81 */ + isapnp_set_csn(ymf71x->pnp_card, 0x81); + /* Set card to SLEEP state */ + isapnp_enable_card(ymf71x->pnp_card, ISAPNP_CARD_FORCE_SLEEP); + } + } + ymf71x->configidx = val; + } + if (addr == 0xA79) { + if ((ymf71x->configidx == 0x21) && (val & 0x01)) { + ymf71x_log(ymf71x->log, "Enable internal RAM write\n"); + ymf71x->ramwrite_enable = 1; + } + if ((ymf71x->configidx == 0x21) && (val == 0x00)) { + ymf71x_log(ymf71x->log, "Disable internal RAM write\n"); + isapnp_update_card_rom(ymf71x->pnp_card, &ymf71x->ram_data[0], 512); + } + if ((ymf71x->configidx == 0x20) && (ymf71x->ramwrite_enable == 0x01)) { + ymf71x_log(ymf71x->log, "Write to internal RAM addr %04X, val %02X\n", ymf71x->ram_addr, val); + ymf71x->ram_data[ymf71x->ram_addr++] = val; + } + } +} + +static uint8_t +ymf71x_wss_read(uint16_t addr, void *priv) +{ + ymf71x_t *ymf71x = (ymf71x_t *) priv; + uint8_t ret = 0x00; + uint8_t port = addr - ymf71x->cur_wss_addr; + + switch (port) { + case 0: + switch (ymf71x->cur_wss_irq) { + case 7: + ret |= 0x08; + break; + case 9: + ret |= 0x10; + break; + case 10: + ret |= 0x18; + break; + case 11: + ret |= 0x20; + break; + default: + break; + } + switch (ymf71x->cur_wss_dma) { + case 0: + ret |= 0x01; + break; + case 1: + ret |= 0x02; + break; + case 3: + ret |= 0x03; + break; + default: + break; + } + break; + case 3: + ret = 0x04; + break; + default: + ret = 0x04; + break; + } + ymf71x_log(ymf71x->log, "WSS Read: addr = %02X, ret = %02X\n", addr, ret); + return ret; + +} + +static void +ymf71x_wss_write(uint16_t addr, uint8_t val, void *priv) +{ + ymf71x_t *ymf71x = (ymf71x_t *) priv; + uint8_t port = addr - ymf71x->cur_wss_addr; + + ymf71x_log(ymf71x->log, "WSS Write: addr = %02X, val = %02X\n", addr, val); + switch (port) { + case 0: + break; + default: + break; + } +} + +static void +ymf71x_update_mastervol(void *priv) +{ + ymf71x_t *ymf71x = (ymf71x_t *) priv; + /* Master volume attenuation */ + if (ymf71x->regs[0x07] & 0x80) + ymf71x->master_l = 0; + else + ymf71x->master_l = ymf71x_att_2dbstep_4bits[ymf71x->regs[0x07] & 0x0F] / 32767.0; + + if (ymf71x->regs[0x08] & 0x80) + ymf71x->master_r = 0; + else + ymf71x->master_r = ymf71x_att_2dbstep_4bits[ymf71x->regs[0x08] & 0x0F] / 32767.0; +} + +static void +ymf71x_reg_write(uint16_t addr, uint8_t val, void *priv) +{ + ymf71x_t *ymf71x = (ymf71x_t *) priv; + uint8_t port = addr - ymf71x->cur_ctrl_addr; + + switch (port) { + case 0x00: /* Index */ + ymf71x->index = val; + break; + case 0x01: /* Data */ + if (ymf71x->index <= ymf71x->max_reg) { + switch (ymf71x->index) { + case 0x01: /* Power Management */ + ymf71x->regs[0x01] = val; + break; + case 0x02: /* System Control */ + ymf71x->regs[0x02] = val; + break; + case 0x03: /* Interrupt Channel Config */ + ymf71x->regs[0x03] = val; + break; + case 0x04: /* IRQ-A Status (RO) */ + break; + case 0x05: /* IRQ-B Status (RO) */ + break; + case 0x06: /* DMA Config */ + ymf71x->regs[0x06] = val; + break; + case 0x07: /* Master Volume Left Channel */ + ymf71x->regs[0x07] = val; + ymf71x_update_mastervol(ymf71x); + break; + case 0x08: /* Master Volume Right Channel */ + ymf71x->regs[0x08] = val; + ymf71x_update_mastervol(ymf71x); + break; + case 0x09: /* Mic Volume */ + ymf71x->regs[0x09] = val; + break; + case 0x0A: /* Miscellaneous */ + ymf71x->regs[0x0A] = ((val & 0xf0) | ymf71x->type); + break; + case 0x0B ... 0x0E: /* WSS DMA Base Counter */ + ymf71x->regs[ymf71x->index] = val; + break; + case 0x0F: /* WSS Interrupt Scan (SA3) */ + ymf71x->regs[0x0F] = val; + break; + case 0x10: /* SB Internal State Scan (SA3) */ + ymf71x->regs[0x10] = val; + break; + case 0x11: /* SB Internal State Scan (SA3) */ + ymf71x->regs[0x11] = val; + break; + case 0x12: /* Digital Block Partial Power Down (SA3) */ + ymf71x->regs[0x12] = val; + break; + case 0x13: /* Analog Block Partial Power Down (SA3) */ + ymf71x->regs[0x13] = val; + break; + case 0x14: /* 3D Enhanced Control Wide (SA3) */ + ymf71x->regs[0x14] = val; + break; + case 0x15: /* 3D Enhanced Control Bass (SA3) */ + ymf71x->regs[0x15] = val; + break; + case 0x16: /* 3D Enhanced Control Treble (SA3) */ + ymf71x->regs[0x16] = val; + break; + case 0x17: /* Hardware Volume Interrupt Channel Config (SA3) */ + ymf71x->regs[0x17] = val; + break; + default: + break; + } + } + break; + default: + break; + } + ymf71x_log(ymf71x->log, "Write: addr = %02X, val = %02X\n", addr, val); +} + +static uint8_t +ymf71x_reg_read(uint16_t addr, void *priv) +{ + ymf71x_t *ymf71x = (ymf71x_t *) priv; + uint8_t temp = 0xFF; + uint8_t port = addr - ymf71x->cur_ctrl_addr; + + switch (port) { + case 0x00: /* Index */ + temp = ymf71x->index; + break; + case 0x01: /* Data */ + if (ymf71x->index <= ymf71x->max_reg) { + if (ymf71x->index == 0x04) { /* Read IRQ-A status reg */ + temp = 0; + if (ymf71x->regs[0x03] & 0x01) + temp |= ((ymf71x->ad1848.regs[24] >> 4) & 0x07); + if (ymf71x->regs[0x03] & 0x02) + temp |= ((ymf71x->sb->dsp.sb_irq8) ? 8: 0); + } + else if (ymf71x->index == 0x05) { /* Read IRQ-B status reg */ + temp = 0; + if (ymf71x->regs[0x03] & 0x10) + temp |= ((ymf71x->ad1848.regs[24] >> 4) & 0x07); + if (ymf71x->regs[0x03] & 0x20) + temp |= ((ymf71x->sb->dsp.sb_irq8) ? 8: 0); + } + else + temp = ymf71x->regs[ymf71x->index]; + } + break; + default: + break; + } + + ymf71x_log(ymf71x->log, "Read: addr = %02X, ret = %02X\n", addr, temp); + return temp; +} + +static void +ymf71x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + ymf71x_t *ymf71x = (ymf71x_t *) priv; + + ymf71x_log(ymf71x->log, "PnP Config changed\n"); + + switch (ld) { + case 0: /* WSS/OPL3/SBPro/MPU401/CTRL */ + if (ymf71x->cur_wss_addr) { + io_removehandler(ymf71x->cur_wss_addr, 0x0004, ymf71x_wss_read, NULL, NULL, ymf71x_wss_write, NULL, NULL, ymf71x); + io_removehandler(ymf71x->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &ymf71x->ad1848); + ymf71x->cur_wss_addr = 0; + ymf71x->cur_wss_enabled = 0; + } + + if (ymf71x->cur_opl_addr) { + io_removehandler(ymf71x->cur_opl_addr, 4, ymf71x->sb->opl.read, NULL, NULL, ymf71x->sb->opl.write, NULL, NULL, ymf71x->sb->opl.priv); + ymf71x->cur_opl_addr = 0; + } + + if (ymf71x->cur_sb_addr) { + sb_dsp_setaddr(&ymf71x->sb->dsp, 0); + io_removehandler(ymf71x->cur_sb_addr, 4, ymf71x->sb->opl.read, NULL, NULL, ymf71x->sb->opl.write, NULL, NULL, ymf71x->sb->opl.priv); + io_removehandler(ymf71x->cur_sb_addr + 8, 2, ymf71x->sb->opl.read, NULL, NULL, ymf71x->sb->opl.write, NULL, NULL, ymf71x->sb->opl.priv); + io_removehandler(ymf71x->cur_sb_addr + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, ymf71x->sb); + ymf71x->cur_sb_addr = 0; + } + + if (ymf71x->cur_ctrl_addr) { + io_removehandler(ymf71x->cur_ctrl_addr, 2, ymf71x_reg_read, NULL, NULL, ymf71x_reg_write, NULL, NULL, ymf71x); + } + + ad1848_setirq(&ymf71x->ad1848, 0); + sb_dsp_setirq(&ymf71x->sb->dsp, 0); + + ad1848_setdma(&ymf71x->ad1848, 0); + sb_dsp_setdma8(&ymf71x->sb->dsp, 0); + + if (config->activate) { + if (config->io[0].base != ISAPNP_IO_DISABLED) { + ymf71x->cur_sb_addr = config->io[0].base; + ymf71x_log(ymf71x->log, "Updating SB DSP I/O port, SB Addr = %04X\n", ymf71x->cur_sb_addr); + sb_dsp_setaddr(&ymf71x->sb->dsp, ymf71x->cur_sb_addr); + io_sethandler(ymf71x->cur_sb_addr, 4, ymf71x->sb->opl.read, NULL, NULL, ymf71x->sb->opl.write, NULL, NULL, ymf71x->sb->opl.priv); + io_sethandler(ymf71x->cur_sb_addr + 8, 2, ymf71x->sb->opl.read, NULL, NULL, ymf71x->sb->opl.write, NULL, NULL, ymf71x->sb->opl.priv); + io_sethandler(ymf71x->cur_sb_addr + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, ymf71x->sb); + } + + if (config->io[1].base != ISAPNP_IO_DISABLED) { + ymf71x->cur_wss_addr = config->io[1].base; + ymf71x->cur_wss_enabled = 1; + ymf71x_log(ymf71x->log, "Updating WSS I/O port, WSS Addr = %04X\n", ymf71x->cur_wss_addr); + io_sethandler(ymf71x->cur_wss_addr, 0x0004, ymf71x_wss_read, NULL, NULL, ymf71x_wss_write, NULL, NULL, ymf71x); + io_sethandler(ymf71x->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &ymf71x->ad1848); + } + + if (config->io[2].base != ISAPNP_IO_DISABLED) { + ymf71x->cur_opl_addr = config->io[2].base; + ymf71x_log(ymf71x->log, "Updating OPL I/O port, OPL Addr = %04X\n", ymf71x->cur_opl_addr); + io_sethandler(ymf71x->cur_opl_addr, 4, ymf71x->sb->opl.read, NULL, NULL, ymf71x->sb->opl.write, NULL, NULL, ymf71x->sb->opl.priv); + } + + if (config->io[3].base != ISAPNP_IO_DISABLED) { + ymf71x->cur_mpu401_addr = config->io[3].base; + ymf71x_log(ymf71x->log, "Updating MPU401 I/O port, MPU Addr = %04X\n", ymf71x->cur_mpu401_addr); + mpu401_change_addr(ymf71x->mpu, ymf71x->cur_mpu401_addr); + } + + if (config->io[4].base != ISAPNP_IO_DISABLED) { + ymf71x->cur_ctrl_addr = config->io[4].base; + ymf71x_log(ymf71x->log, "Updating CTRL I/O port, CTRL Addr = %04X\n", ymf71x->cur_ctrl_addr); + io_sethandler(ymf71x->cur_ctrl_addr, 2, ymf71x_reg_read, NULL, NULL, ymf71x_reg_write, NULL, NULL, ymf71x); + } + + if (config->irq[0].irq != ISAPNP_IRQ_DISABLED) { + if (ymf71x->regs[0x03] & 0x01) { + ad1848_setirq(&ymf71x->ad1848, config->irq[0].irq); + ymf71x->cur_wss_irq = config->irq[0].irq; + ymf71x_log(ymf71x->log, "Setting WSS IRQ to IRQ-A (%04X)\n", ymf71x->cur_wss_irq); + } + if (ymf71x->regs[0x03] & 0x02) { + sb_dsp_setirq(&ymf71x->sb->dsp, config->irq[0].irq); + ymf71x->cur_sb_irq = config->irq[0].irq; + ymf71x_log(ymf71x->log, "Setting SB IRQ to IRQ-A (%04X)\n", ymf71x->cur_sb_irq); + } + if (ymf71x->regs[0x03] & 0x04) { + mpu401_setirq(ymf71x->mpu, config->irq[0].irq); + ymf71x->cur_mpu401_irq = config->irq[0].irq; + ymf71x_log(ymf71x->log, "Setting MPU401 IRQ to IRQ-A (%04X)\n", ymf71x->cur_mpu401_irq); + } + } + + if (config->irq[1].irq != ISAPNP_IRQ_DISABLED) { + if (ymf71x->regs[0x03] & 0x10) { + ad1848_setirq(&ymf71x->ad1848, config->irq[1].irq); + ymf71x->cur_wss_irq = config->irq[1].irq; + ymf71x_log(ymf71x->log, "Setting WSS IRQ to IRQ-B (%04X)\n", ymf71x->cur_wss_irq); + } + if (ymf71x->regs[0x03] & 0x20) { + sb_dsp_setirq(&ymf71x->sb->dsp, config->irq[1].irq); + ymf71x->cur_sb_irq = config->irq[1].irq; + ymf71x_log(ymf71x->log, "Setting SB IRQ to IRQ-B (%04X)\n", ymf71x->cur_sb_irq); + } + if (ymf71x->regs[0x03] & 0x40) { + mpu401_setirq(ymf71x->mpu, config->irq[1].irq); + ymf71x->cur_mpu401_irq = config->irq[1].irq; + ymf71x_log(ymf71x->log, "Setting MPU401 IRQ to IRQ-B (%04X)\n", ymf71x->cur_mpu401_irq); + } + } + + if (config->dma[0].dma != ISAPNP_DMA_DISABLED) { + if (ymf71x->regs[0x06] & 0x01) { + ad1848_setdma(&ymf71x->ad1848, config->dma[0].dma); + ymf71x->cur_wss_dma = config->dma[0].dma; + ymf71x_log(ymf71x->log, "Setting WSS DMA to DMA-A (%04X)\n", ymf71x->cur_wss_dma); + } + if (ymf71x->regs[0x06] & 0x04) { + sb_dsp_setdma8(&ymf71x->sb->dsp, config->dma[0].dma); + ymf71x->cur_sb_dma = config->dma[0].dma; + ymf71x_log(ymf71x->log, "Setting SB DMA to DMA-A (%04X)\n", ymf71x->cur_sb_dma); + } + } + + if (config->dma[1].dma != ISAPNP_DMA_DISABLED) { + if (ymf71x->regs[0x06] & 0x10) { + ad1848_setdma(&ymf71x->ad1848, config->dma[1].dma); + ymf71x->cur_wss_dma = config->dma[1].dma; + ymf71x_log(ymf71x->log, "Setting WSS DMA to DMA-B (%04X)\n", ymf71x->cur_wss_dma); + } + if (ymf71x->regs[0x06] & 0x40) { + sb_dsp_setdma8(&ymf71x->sb->dsp, config->dma[1].dma); + ymf71x->cur_sb_dma = config->dma[1].dma; + ymf71x_log(ymf71x->log, "Setting SB DMA to DMA-B (%04X)\n", ymf71x->cur_sb_dma); + } + } + } + break; + + case 1: /* Game Port */ + if (ymf71x->gameport) + gameport_remap(ymf71x->gameport, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0); + break; + default: + break; + } +} + +void +ymf71x_filter_cd_audio(int channel, double *buffer, void *priv) +{ + ymf71x_t *ymf71x = (ymf71x_t *) priv; + const double cd_vol = channel ? ymf71x->ad1848.cd_vol_r : ymf71x->ad1848.cd_vol_l; + double master = channel ? ymf71x->master_r : ymf71x->master_l; + double c = ((*buffer * cd_vol / 3.0) * master) / 65536.0; + double bass_treble; + + if ((ymf71x->regs[0x15] & 0x07) != 0x00) { + bass_treble = ymf71x_bass_treble_3bits[(ymf71x->regs[0x15] & 0x07)]; + + c += (low_iir(2, 0, c) * bass_treble); + } + + if (((ymf71x->regs[0x15] >> 4) & 0x07) != 0x00) { + bass_treble = ymf71x_bass_treble_3bits[((ymf71x->regs[0x15] >> 4) & 0x07)]; + + c += (low_iir(2, 1, c) * bass_treble); + } + + if ((ymf71x->regs[0x16] & 0x07) != 0x00) { + bass_treble = ymf71x_bass_treble_3bits[ymf71x->regs[0x16] & 0x07]; + + c += (high_iir(2, 0, c) * bass_treble); + } + + if (((ymf71x->regs[0x16] >> 4) & 0x07) != 0x00) { + bass_treble = ymf71x_bass_treble_3bits[(ymf71x->regs[0x16] >> 4) & 0x07]; + + c += (high_iir(2, 1, c) * bass_treble); + } + + *buffer = c; +} + +static void +ymf71x_filter_opl(void *priv, double *out_l, double *out_r) +{ + ymf71x_t *ymf71x = (ymf71x_t *) priv; + double bass_treble; + + /* Don't play audio if the FM DAC or OPL3 digital sections are powered down */ + if ( (!(ymf71x->regs[0x01] & 0x23)) && (!(ymf71x->regs[0x12] & 0x10)) && (!(ymf71x->regs[0x13] & 0x10)) ) { + if ((ymf71x->regs[0x15] & 0x07) != 0x00) { + bass_treble = ymf71x_bass_treble_3bits[(ymf71x->regs[0x15] & 0x07)]; + + *out_l += (low_iir(1, 0, *out_l) * bass_treble); + } + + if (((ymf71x->regs[0x15] >> 4) & 0x07) != 0x00) { + bass_treble = ymf71x_bass_treble_3bits[((ymf71x->regs[0x15] >> 4) & 0x07)]; + + *out_r += (low_iir(1, 1, *out_r) * bass_treble); + } + + if ((ymf71x->regs[0x16] & 0x07) != 0x00) { + bass_treble = ymf71x_bass_treble_3bits[ymf71x->regs[0x16] & 0x07]; + + *out_l += (high_iir(1, 0, *out_l) * bass_treble); + } + + if (((ymf71x->regs[0x16] >> 4) & 0x07) != 0x00) { + bass_treble = ymf71x_bass_treble_3bits[(ymf71x->regs[0x16] >> 4) & 0x07]; + + *out_r += (high_iir(1, 1, *out_r) * bass_treble); + } + + *out_l *= ymf71x->master_l; + *out_r *= ymf71x->master_r; + + if (ymf71x->cur_wss_enabled) { + ad1848_filter_channel((void *) &ymf71x->ad1848, AD1848_AUX2, out_l, out_r); + } + } +} + +static void +ymf71x_get_buffer(int32_t *buffer, int len, void *priv) +{ + ymf71x_t *ymf71x = (ymf71x_t *) priv; + + /* wss part */ + + /* Don't play audio if the WSS Playback analog or digital sections are powered down */ + if ( (!(ymf71x->regs[0x01] & 0x23)) && (!(ymf71x->regs[0x12] & 0x04)) && (!(ymf71x->regs[0x13] & 0x04)) ) { + ad1848_update(&ymf71x->ad1848); + for (int c = 0; c < len * 2; c += 2) { + double out_l = 0.0; + double out_r = 0.0; + double bass_treble; + + out_l += (ymf71x->ad1848.buffer[c] * ymf71x->master_l); + out_r += (ymf71x->ad1848.buffer[c +1] * ymf71x->master_r); + + if ((ymf71x->regs[0x15] & 0x07) != 0x00) { + bass_treble = ymf71x_bass_treble_3bits[(ymf71x->regs[0x15] & 0x07)]; + + out_l += (low_iir(0, 0, out_l) * bass_treble); + } + + if (((ymf71x->regs[0x15] >> 4) & 0x07) != 0x00) { + bass_treble = ymf71x_bass_treble_3bits[((ymf71x->regs[0x15] >> 4) & 0x07)]; + + out_r += (low_iir(0, 1, out_r) * bass_treble); + } + + if ((ymf71x->regs[0x16] & 0x07) != 0x00) { + bass_treble = ymf71x_bass_treble_3bits[ymf71x->regs[0x16] & 0x07]; + + out_l += (high_iir(0, 0, out_l) * bass_treble); + } + + if (((ymf71x->regs[0x16] >> 4) & 0x07) != 0x00) { + bass_treble = ymf71x_bass_treble_3bits[(ymf71x->regs[0x16] >> 4) & 0x07]; + + out_r += (high_iir(0, 1, out_r) * bass_treble); + } + + out_l *= ymf71x->master_l; + out_r *= ymf71x->master_r; + + buffer[c] += (int32_t) out_l; + buffer[c + 1] += (int32_t) out_r; + } + + ymf71x->ad1848.pos = 0; + } + + /* sbprov2 part */ + /* Don't play audio if the SB Compatibility analog or digital sections are powered down */ + if ( (!(ymf71x->regs[0x01] & 0x23)) && (!(ymf71x->regs[0x12] & 0x02)) && (!(ymf71x->regs[0x13] & 0x02)) ) { + sb_get_buffer_sbpro(buffer, len, ymf71x->sb); + } +} + +static void * +ymf71x_init(const device_t *info) +{ + ymf71x_t *ymf71x = calloc(1, sizeof(ymf71x_t)); + + ymf71x->type = (info->local & 0x0F); + + ymf71x->cur_wss_addr = 0; + ymf71x->cur_sb_addr = 0; + ymf71x->cur_sb_irq = 5; + ymf71x->cur_wss_enabled = 0; + ymf71x->cur_sb_dma = 1; + ymf71x->cur_mpu401_irq = 5; + ymf71x->cur_mpu401_addr = 0; + ymf71x->cur_wss_dma = 0; + ymf71x->cur_wss_irq = 11; + + ymf71x->regs[0x00] = 0xFF; + ymf71x->regs[0x01] = 0x00; + ymf71x->regs[0x02] = 0x00; + ymf71x->regs[0x03] = 0x69; /* IRQ-A = WSS + OPL3, IRQ-B = SB+MPU401 */ + ymf71x->regs[0x04] = 0x00; + ymf71x->regs[0x05] = 0x00; + ymf71x->regs[0x06] = 0x61; /* DMA-A = WSS Playback, DMA-B = WSS Capture + SBPro */ + ymf71x->regs[0x07] = 0x07; + ymf71x->regs[0x08] = 0x07; + ymf71x->regs[0x09] = 0x88; + ymf71x->regs[0x0A] = (0x80 | ymf71x->type); + ymf71x->regs[0x0B] = 0xFF; + ymf71x->regs[0x0C] = 0xFF; + ymf71x->regs[0x0D] = 0xFF; + ymf71x->regs[0x0E] = 0xFF; + ymf71x->regs[0x0F] = 0x00; + ymf71x->regs[0x10] = 0x00; + ymf71x->regs[0x11] = 0x00; + ymf71x->regs[0x12] = 0x00; + ymf71x->regs[0x13] = 0x00; + ymf71x->regs[0x14] = 0x00; + ymf71x->regs[0x15] = 0x00; + ymf71x->regs[0x16] = 0x00; + ymf71x->regs[0x17] = 0x00; + + if (ymf71x->type == 0x02) + ymf71x->max_reg = 0x17; + else + ymf71x->max_reg = 0x0E; + + ymf71x->log = log_open("YMF71x"); + + ymf71x->gameport = gameport_add(&gameport_pnp_device); + + ad1848_init(&ymf71x->ad1848, AD1848_TYPE_CS4231); + + ymf71x->sb = calloc(1, sizeof(sb_t)); + ymf71x->sb->opl_enabled = 1; + + sb_dsp_set_real_opl(&ymf71x->sb->dsp, 1); + sb_dsp_init(&ymf71x->sb->dsp, SBPRO2_DSP_302, SB_SUBTYPE_DEFAULT, ymf71x); + sb_ct1345_mixer_reset(ymf71x->sb); + + ymf71x->sb->opl_mixer = ymf71x; + ymf71x->sb->opl_mix = ymf71x_filter_opl; + + fm_driver_get(FM_YMF262, &ymf71x->sb->opl); + + sound_add_handler(ymf71x_get_buffer, ymf71x); + music_add_handler(sb_get_music_buffer_sbpro, ymf71x->sb); + ad1848_set_cd_audio_channel(&ymf71x->ad1848, AD1848_AUX1); + sound_set_cd_audio_filter(NULL, NULL); /* Seems to be necessary for the filter below to apply */ + sound_set_cd_audio_filter(ymf71x_filter_cd_audio, ymf71x); + + ymf71x->mpu = (mpu_t *) calloc(1, sizeof(mpu_t)); + mpu401_init(ymf71x->mpu, ymf71x->cur_mpu401_addr, ymf71x->cur_mpu401_irq, M_UART, device_get_config_int("receive_input401")); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &ymf71x->sb->dsp); + + if (!(info->local & YMF71X_NO_EEPROM)) { + const char *pnp_rom_file = NULL; + uint16_t pnp_rom_len = 512; + switch (info->local) { + case 0x01: + pnp_rom_file = PNP_ROM_YMF718; + break; + + case 0x02: + pnp_rom_file = PNP_ROM_YMF719; + break; + + default: + break; + } + + uint8_t *pnp_rom = NULL; + if (pnp_rom_file) { + FILE *fp = rom_fopen(pnp_rom_file, "rb"); + if (fp) { + if (fread(ymf71x->pnp_rom, 1, pnp_rom_len, fp) == pnp_rom_len) + pnp_rom = ymf71x->pnp_rom; + fclose(fp); + } + } + ymf71x->pnp_card = isapnp_add_card(pnp_rom, sizeof(ymf71x->pnp_rom), ymf71x_pnp_config_changed, + NULL, NULL, NULL, ymf71x); + } + else + ymf71x->pnp_card = isapnp_add_card(NULL, 0, ymf71x_pnp_config_changed, NULL, NULL, NULL, ymf71x); + + io_sethandler(0x0279, 0x0001, NULL, NULL, NULL, ymf71x_config_write, NULL, NULL, ymf71x); + io_sethandler(0x0A79, 0x0001, NULL, NULL, NULL, ymf71x_config_write, NULL, NULL, ymf71x); + + ymf71x_update_mastervol(ymf71x); + + return ymf71x; +} + +static void +ymf71x_close(void *priv) +{ + ymf71x_t *ymf71x = (ymf71x_t *) priv; + + if (ymf71x->log != NULL) { + log_close(ymf71x->log); + ymf71x->log = NULL; + } + + sb_close(ymf71x->sb); + free(ymf71x->mpu); + free(priv); +} + +static int +ymf718_available(void) +{ + return rom_present(PNP_ROM_YMF718); +} + +static int +ymf719_available(void) +{ + return rom_present(PNP_ROM_YMF719); +} + +static void +ymf71x_speed_changed(void *priv) +{ + ymf71x_t *ymf71x = (ymf71x_t *) priv; + + ad1848_speed_changed(&ymf71x->ad1848); + sb_speed_changed(ymf71x->sb); +} + +static const device_config_t ymf71x_config[] = { + // clang-format off + { + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "receive_input401", + .description = "Receive MIDI input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t ymf715_onboard_device = { + .name = "Yamaha YMF-715 Onboard (OPL3-SA3)", + .internal_name = "ymf715_onboard", + .flags = DEVICE_ISA16, + .local = 0x102, + .init = ymf71x_init, + .close = ymf71x_close, + .reset = NULL, + .available = NULL, + .speed_changed = ymf71x_speed_changed, + .force_redraw = NULL, + .config = ymf71x_config +}; + +const device_t ymf718_device = { + .name = "Yamaha YMF-718 (OPL3-SA2)", + .internal_name = "ymf718", + .flags = DEVICE_ISA16, + .local = 0x01, + .init = ymf71x_init, + .close = ymf71x_close, + .reset = NULL, + .available = ymf718_available, + .speed_changed = ymf71x_speed_changed, + .force_redraw = NULL, + .config = ymf71x_config +}; + +const device_t ymf719_device = { + .name = "Yamaha YMF-719 (OPL3-SA3)", + .internal_name = "ymf719", + .flags = DEVICE_ISA16, + .local = 0x02, + .init = ymf71x_init, + .close = ymf71x_close, + .reset = NULL, + .available = ymf719_available, + .speed_changed = ymf71x_speed_changed, + .force_redraw = NULL, + .config = ymf71x_config +}; diff --git a/src/sound/sndio.c b/src/sound/sndio.c index 1161ff6a6..6363163a2 100644 --- a/src/sound/sndio.c +++ b/src/sound/sndio.c @@ -1,17 +1,16 @@ /* - * 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. * - * Interface to sndio + * Interface to sndio * + * Authors: Nishi * - * Authors: Nishi - * - * Copyright 2025 Nishi. + * Copyright 2025 Nishi. */ #include #include diff --git a/src/sound/sound.c b/src/sound/sound.c index 0abcb5d08..9373f067e 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -8,8 +8,6 @@ * * Sound emulation core. * - * - * * Authors: Sarah Walker, * Miran Grca, * Jasmine Iwanek, @@ -95,7 +93,6 @@ static int cd_thread_enable = 0; static thread_t *sound_fdd_thread_h; static event_t *sound_fdd_event; static event_t *sound_fdd_start_event; -static int16_t fdd_out_buffer[SOUNDBUFLEN * 2]; static volatile int fddaudioon = 0; static int fdd_thread_enable = 0; @@ -168,6 +165,8 @@ static const SOUND_CARD sound_cards[] = { { &sb_vibra16xv_device }, { &wss_device }, { &ymf701_device }, + { &ymf718_device }, + { &ymf719_device }, /* MCA */ { &adlib_mca_device }, { &ess_chipchat_16_mca_device }, diff --git a/src/sound/xaudio2.c b/src/sound/xaudio2.c index 07cce3835..8596c2a49 100644 --- a/src/sound/xaudio2.c +++ b/src/sound/xaudio2.c @@ -1,18 +1,16 @@ /* - * 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. * - * Interface to the XAudio2 audio processing library. + * Interface to the XAudio2 audio processing library. * + * Authors: Cacodemon345 * - * - * Authors: Cacodemon345 - * - * Copyright 2022 Cacodemon345. + * Copyright 2022 Cacodemon345. */ #include #include diff --git a/src/unix/dummy_cdrom_ioctl.c b/src/unix/dummy_cdrom_ioctl.c index 8dffc6758..af8679ecc 100644 --- a/src/unix/dummy_cdrom_ioctl.c +++ b/src/unix/dummy_cdrom_ioctl.c @@ -8,8 +8,6 @@ * * Win32 CD-ROM support via IOCTL. * - * - * * Authors: TheCollector1995, , * Miran Grca, * diff --git a/src/unix/unix.c b/src/unix/unix.c index 70cf5b87c..ee13284fd 100644 --- a/src/unix/unix.c +++ b/src/unix/unix.c @@ -405,11 +405,19 @@ path_append_filename(char *dest, const char *s1, const char *s2) int plat_dir_check(char *path) { - struct stat dummy; - if (stat(path, &dummy) < 0) { + struct stat stats; + if (stat(path, &stats) < 0) return 0; - } - return S_ISDIR(dummy.st_mode); + return S_ISDIR(stats.st_mode); +} + +int +plat_file_check(const char *path) +{ + struct stat stats; + if (stat(path, &stats) < 0) + return 0; + return !S_ISDIR(stats.st_mode); } int diff --git a/src/unix/unix_cdrom.c b/src/unix/unix_cdrom.c index 09aaa5092..daf13cb9a 100644 --- a/src/unix/unix_cdrom.c +++ b/src/unix/unix_cdrom.c @@ -8,15 +8,12 @@ * * Handle the platform-side of CDROM/RDisk/MO drives. * - * - * * Authors: Miran Grca, * Fred N. van Kempen, * * Copyright 2016-2018 Miran Grca. * Copyright 2017-2018 Fred N. van Kempen. */ - #include #include #include diff --git a/src/unix/unix_serial_passthrough.c b/src/unix/unix_serial_passthrough.c index fb74f67b3..0fcfbe5b1 100644 --- a/src/unix/unix_serial_passthrough.c +++ b/src/unix/unix_serial_passthrough.c @@ -1,21 +1,19 @@ /* - * 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. * - * Definitions for platform specific serial to host passthrough + * Definitions for platform specific serial to host passthrough * + * Authors: Andreas J. Reichel , + * Jasmine Iwanek * - * Authors: Andreas J. Reichel , - * Jasmine Iwanek - * - * Copyright 2021 Andreas J. Reichel. - * Copyright 2021-2025 Jasmine Iwanek. + * Copyright 2021 Andreas J. Reichel. + * Copyright 2021-2025 Jasmine Iwanek. */ - #ifndef __APPLE__ # define _XOPEN_SOURCE 500 # define _DEFAULT_SOURCE 1 diff --git a/src/upi42.c b/src/upi42.c index 50f5c44c9..f29f8a307 100644 --- a/src/upi42.c +++ b/src/upi42.c @@ -8,8 +8,6 @@ * * Intel UPI-42/MCS-48 microcontroller emulation. * - * - * * Authors: RichardG, * * Copyright 2022 RichardG. @@ -875,7 +873,7 @@ upi42_exec(void *priv) } /* Fetch instruction. */ - uint32_t fetchdat = *((uint32_t *) &upi42->rom[upi42->pc]); + uint32_t fetchdat = AS_U32(upi42->rom[upi42->pc]); /* Decode instruction. */ uint8_t insn = fetchdat & 0xff; diff --git a/src/usb.c b/src/usb.c index 222062f4f..c305f4806 100644 --- a/src/usb.c +++ b/src/usb.c @@ -9,8 +9,6 @@ * Universal Serial Bus emulation (currently dummy UHCI and * OHCI). * - * - * * Authors: Miran Grca, * * Copyright 2020 Miran Grca. diff --git a/src/utils/ini.c b/src/utils/ini.c index 47e792594..3ca4c7943 100644 --- a/src/utils/ini.c +++ b/src/utils/ini.c @@ -8,8 +8,6 @@ * * Configuration file handler. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, @@ -25,7 +23,6 @@ * it on Windows XP, and possibly also Vista. Use the * -DANSI_CFG for use on these systems. */ - #include #include #include diff --git a/src/utils/random.c b/src/utils/random.c index 58abb15eb..6ed6c1d0c 100644 --- a/src/utils/random.c +++ b/src/utils/random.c @@ -9,8 +9,6 @@ * A better random number generation, used for floppy weak bits * and network MAC address generation. * - * - * * Authors: Miran Grca, * * Copyright 2016-2018 Miran Grca. diff --git a/src/video/agpgart.c b/src/video/agpgart.c index bf1976b73..6ce5508a0 100644 --- a/src/video/agpgart.c +++ b/src/video/agpgart.c @@ -8,8 +8,6 @@ * * AGP Graphics Address Remapping Table remapping emulation. * - * - * * Authors: RichardG, * * Copyright 2021 RichardG. diff --git a/src/video/clockgen/vid_clockgen_av9194.c b/src/video/clockgen/vid_clockgen_av9194.c index 951f3519c..2f52db151 100644 --- a/src/video/clockgen/vid_clockgen_av9194.c +++ b/src/video/clockgen/vid_clockgen_av9194.c @@ -10,8 +10,6 @@ * * Used by the S3 86c801 (V7-Mirage) card. * - * - * * Authors: Miran Grca, * * Copyright 2016-2018 Miran Grca. diff --git a/src/video/clockgen/vid_clockgen_icd2061.c b/src/video/clockgen/vid_clockgen_icd2061.c index a7f0286f2..bbb4f306f 100644 --- a/src/video/clockgen/vid_clockgen_icd2061.c +++ b/src/video/clockgen/vid_clockgen_icd2061.c @@ -14,8 +14,6 @@ * Used by ET4000w32/p (Diamond Stealth 32) and the S3 * Vision964 family. * - * - * * Authors: Miran Grca, * * Copyright 2016-2018 Miran Grca. diff --git a/src/video/clockgen/vid_clockgen_ics2494.c b/src/video/clockgen/vid_clockgen_ics2494.c index 33a74fe62..f9f4fbcb1 100644 --- a/src/video/clockgen/vid_clockgen_ics2494.c +++ b/src/video/clockgen/vid_clockgen_ics2494.c @@ -10,8 +10,6 @@ * * Used by the AMI S3 924. * - * - * * Authors: Miran Grca, * * Copyright 2020 Miran Grca. diff --git a/src/video/clockgen/vid_clockgen_ics2595.c b/src/video/clockgen/vid_clockgen_ics2595.c index b5da3d7e2..1ee61eb02 100644 --- a/src/video/clockgen/vid_clockgen_ics2595.c +++ b/src/video/clockgen/vid_clockgen_ics2595.c @@ -8,8 +8,6 @@ * * ICS2595 clock chip emulation. Used by ATI Mach64. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/nv/nv_rivatimer.c b/src/video/nv/nv_rivatimer.c index 12d40c026..b28042eab 100644 --- a/src/video/nv/nv_rivatimer.c +++ b/src/video/nv/nv_rivatimer.c @@ -8,8 +8,6 @@ * * Fast, high-frequency, CPU-independent timer. * - * - * * Authors: Connor Hyde, I need a better email address ;^) * * Copyright 2024-2025 starfrost diff --git a/src/video/ramdac/vid_ramdac_ati68860.c b/src/video/ramdac/vid_ramdac_ati68860.c index 4411f2ee2..0f40a4515 100644 --- a/src/video/ramdac/vid_ramdac_ati68860.c +++ b/src/video/ramdac/vid_ramdac_ati68860.c @@ -28,8 +28,6 @@ * 7 If set can remove "snow" in some cases * (A860_Delay_L ?) ?? * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/ramdac/vid_ramdac_ati68875.c b/src/video/ramdac/vid_ramdac_ati68875.c index 4de0ed3d9..12d39ad05 100644 --- a/src/video/ramdac/vid_ramdac_ati68875.c +++ b/src/video/ramdac/vid_ramdac_ati68875.c @@ -8,8 +8,6 @@ * * Emulation of the Mach32-compatible ATI 68875 RAMDAC and clones. * - * - * * Authors: TheCollector1995. * * Copyright 2022-2023 TheCollector1995. diff --git a/src/video/ramdac/vid_ramdac_att20c49x.c b/src/video/ramdac/vid_ramdac_att20c49x.c index 7815f79be..2d8d6a304 100644 --- a/src/video/ramdac/vid_ramdac_att20c49x.c +++ b/src/video/ramdac/vid_ramdac_att20c49x.c @@ -8,8 +8,6 @@ * * Emulation of a AT&T 20c490/491 and 492/493 RAMDAC. * - * - * * Authors: Miran Grca, * * Copyright 2016-2018 Miran Grca. diff --git a/src/video/ramdac/vid_ramdac_att2xc498.c b/src/video/ramdac/vid_ramdac_att2xc498.c index f52b1432f..141ffa4b4 100644 --- a/src/video/ramdac/vid_ramdac_att2xc498.c +++ b/src/video/ramdac/vid_ramdac_att2xc498.c @@ -8,8 +8,6 @@ * * Emulation of a AT&T 2xc498 RAMDAC. * - * - * * Authors: Miran Grca, * * Copyright 2016-2018 Miran Grca. diff --git a/src/video/ramdac/vid_ramdac_bt481.c b/src/video/ramdac/vid_ramdac_bt481.c index 1b81e2dc7..829d1f5a3 100644 --- a/src/video/ramdac/vid_ramdac_bt481.c +++ b/src/video/ramdac/vid_ramdac_bt481.c @@ -9,8 +9,6 @@ * Emulation of the Brooktree BT481 true colour RAMDAC * family. * - * - * * Authors: TheCollector1995. * * Copyright 2024 TheCollector1995. diff --git a/src/video/ramdac/vid_ramdac_bt48x.c b/src/video/ramdac/vid_ramdac_bt48x.c index 7ae96dfbd..be6499990 100644 --- a/src/video/ramdac/vid_ramdac_bt48x.c +++ b/src/video/ramdac/vid_ramdac_bt48x.c @@ -9,8 +9,6 @@ * Emulation of the Brooktree BT484-485A true colour RAMDAC * family. * - * - * * Authors: Miran Grca, * TheCollector1995, * diff --git a/src/video/ramdac/vid_ramdac_ibm_rgb528.c b/src/video/ramdac/vid_ramdac_ibm_rgb528.c index 2f1d57240..bded466d1 100644 --- a/src/video/ramdac/vid_ramdac_ibm_rgb528.c +++ b/src/video/ramdac/vid_ramdac_ibm_rgb528.c @@ -8,8 +8,6 @@ * * Emulation of the IBM RGB 528 true colour RAMDAC. * - * - * * Authors: Miran Grca, * * Copyright 2020 Miran Grca. diff --git a/src/video/ramdac/vid_ramdac_sc1148x.c b/src/video/ramdac/vid_ramdac_sc1148x.c index 0ebcb49b6..d508787b3 100644 --- a/src/video/ramdac/vid_ramdac_sc1148x.c +++ b/src/video/ramdac/vid_ramdac_sc1148x.c @@ -10,8 +10,6 @@ * * Used by the S3 911 and 924 chips. * - * - * * Authors: TheCollector1995, * * Copyright 2020 TheCollector1995. diff --git a/src/video/ramdac/vid_ramdac_sc1502x.c b/src/video/ramdac/vid_ramdac_sc1502x.c index 972e0d895..e427cdfb6 100644 --- a/src/video/ramdac/vid_ramdac_sc1502x.c +++ b/src/video/ramdac/vid_ramdac_sc1502x.c @@ -10,8 +10,6 @@ * * Used by the TLIVESA1 driver for ET4000. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/ramdac/vid_ramdac_sdac.c b/src/video/ramdac/vid_ramdac_sdac.c index 4e6deacdc..2b2890307 100644 --- a/src/video/ramdac/vid_ramdac_sdac.c +++ b/src/video/ramdac/vid_ramdac_sdac.c @@ -8,8 +8,6 @@ * * 87C716 'SDAC' true colour RAMDAC emulation. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/ramdac/vid_ramdac_stg1702.c b/src/video/ramdac/vid_ramdac_stg1702.c index 85d492ce7..8a2d008dd 100644 --- a/src/video/ramdac/vid_ramdac_stg1702.c +++ b/src/video/ramdac/vid_ramdac_stg1702.c @@ -8,8 +8,6 @@ * * STG1702 true colour RAMDAC emulation. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/ramdac/vid_ramdac_tkd8001.c b/src/video/ramdac/vid_ramdac_tkd8001.c index c8ad1c421..7b1ab4d36 100644 --- a/src/video/ramdac/vid_ramdac_tkd8001.c +++ b/src/video/ramdac/vid_ramdac_tkd8001.c @@ -8,8 +8,6 @@ * * Trident TKD8001 RAMDAC emulation. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/ramdac/vid_ramdac_tvp3026.c b/src/video/ramdac/vid_ramdac_tvp3026.c index bd5a83fd0..1958fa588 100644 --- a/src/video/ramdac/vid_ramdac_tvp3026.c +++ b/src/video/ramdac/vid_ramdac_tvp3026.c @@ -9,7 +9,6 @@ * Emulation of the Texas Instruments TVP3026 true colour RAMDAC * family. * - * * TODO: Clock and other parts. * * Authors: TheCollector1995, diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index 7b747ddc0..d521c07d5 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -9,8 +9,6 @@ * Emulation of the 8514/A card from IBM for the MCA bus and * ISA bus clones. * - * - * * Authors: TheCollector1995. * * Copyright 2022-2024 TheCollector1995. diff --git a/src/video/vid_ati18800.c b/src/video/vid_ati18800.c index 11124a35b..a7d479235 100644 --- a/src/video/vid_ati18800.c +++ b/src/video/vid_ati18800.c @@ -8,8 +8,6 @@ * * ATI 18800 emulation (VGA Edge-16) * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_ati28800.c b/src/video/vid_ati28800.c index 205d934ee..2fe46bea3 100644 --- a/src/video/vid_ati28800.c +++ b/src/video/vid_ati28800.c @@ -8,8 +8,6 @@ * * ATI 28800 emulation (VGA Charger and Korean VGA) * - * - * * Authors: Sarah Walker, * Miran Grca, * greatpsycho, diff --git a/src/video/vid_ati_eeprom.c b/src/video/vid_ati_eeprom.c index a057f1f39..84cbffedb 100644 --- a/src/video/vid_ati_eeprom.c +++ b/src/video/vid_ati_eeprom.c @@ -8,8 +8,6 @@ * * Emulation of the EEPROM on select ATI cards. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index 324023db1..6a9b9ea34 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -8,8 +8,6 @@ * * ATi Mach64 graphics card emulation. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 24293ab1d..b0642c0de 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -9,8 +9,6 @@ * Emulation of the 8514/A-compatible Mach8 and Mach32 graphics * chips from ATI for the ISA/VLB/MCA/PCI buses. * - * - * * Authors: TheCollector1995. * * Copyright 2022-2024 TheCollector1995. diff --git a/src/video/vid_bochs_vbe.c b/src/video/vid_bochs_vbe.c index 0ea268ef7..ea0b8872b 100644 --- a/src/video/vid_bochs_vbe.c +++ b/src/video/vid_bochs_vbe.c @@ -23,7 +23,6 @@ * * See https://gitlab.freedesktop.org/xorg/lib/libxcvt/-/blob/master/COPYING for libxcvt license details */ - #include #include #include diff --git a/src/video/vid_cga_colorplus.c b/src/video/vid_cga_colorplus.c index 15d53d543..8b5f1daf7 100644 --- a/src/video/vid_cga_colorplus.c +++ b/src/video/vid_cga_colorplus.c @@ -8,8 +8,6 @@ * * Plantronics ColorPlus emulation. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_cga_comp.c b/src/video/vid_cga_comp.c index a316f79fb..2e3fb8d68 100644 --- a/src/video/vid_cga_comp.c +++ b/src/video/vid_cga_comp.c @@ -9,8 +9,6 @@ * IBM CGA composite filter, borrowed from reenigne's DOSBox * patch and ported to C. * - * - * * Authors: reenigne, * Miran Grca, * diff --git a/src/video/vid_cga_compaq.c b/src/video/vid_cga_compaq.c index 81b063248..6168b7752 100644 --- a/src/video/vid_cga_compaq.c +++ b/src/video/vid_cga_compaq.c @@ -8,8 +8,6 @@ * * Emulation of the Compaq CGA graphics cards. * - * - * * Authors: John Elliott, * Sarah Walker, * Miran Grca, diff --git a/src/video/vid_cga_compaq_plasma.c b/src/video/vid_cga_compaq_plasma.c index b281cf93f..b894daa9f 100644 --- a/src/video/vid_cga_compaq_plasma.c +++ b/src/video/vid_cga_compaq_plasma.c @@ -8,8 +8,6 @@ * * Emulation of the plasma displays on early Compaq Portables and laptops. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_cga_ncr.c b/src/video/vid_cga_ncr.c index eb4474a40..6b0f15f65 100644 --- a/src/video/vid_cga_ncr.c +++ b/src/video/vid_cga_ncr.c @@ -8,8 +8,6 @@ * * Emulation of the NCR NGA (K511, K201) video cards. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, @@ -20,7 +18,6 @@ * Copyright 2017-2019 Fred N. van Kempen. * Copyright 2020 EngiNerd. */ - #include #include #include diff --git a/src/video/vid_cga_olivetti.c b/src/video/vid_cga_olivetti.c index 147529f6e..4cb845684 100644 --- a/src/video/vid_cga_olivetti.c +++ b/src/video/vid_cga_olivetti.c @@ -9,8 +9,6 @@ * Emulation of the Olivetti OGC 8-bit ISA (GO708) and * M21/M24/M28 16-bit bus (GO317/318/380/709) video cards. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, @@ -21,7 +19,6 @@ * Copyright 2017-2019 Fred N. van Kempen. * Copyright 2020 EngiNerd. */ - #include #include #include diff --git a/src/video/vid_cga_toshiba_t1000.c b/src/video/vid_cga_toshiba_t1000.c index 2fd382272..894d28a56 100644 --- a/src/video/vid_cga_toshiba_t1000.c +++ b/src/video/vid_cga_toshiba_t1000.c @@ -9,8 +9,6 @@ * Implementation of the Toshiba T1000 plasma display, which * has a fixed resolution of 640x200 pixels. * - * - * * Authors: Fred N. van Kempen, * Miran Grca, * John Elliott, diff --git a/src/video/vid_cga_toshiba_t3100e.c b/src/video/vid_cga_toshiba_t3100e.c index e3eb673c8..25f079204 100644 --- a/src/video/vid_cga_toshiba_t3100e.c +++ b/src/video/vid_cga_toshiba_t3100e.c @@ -22,8 +22,6 @@ * 61 50 52 0F 19 06 19 19 02 0D 0B 0C MONO * 2D 28 22 0A 67 00 64 67 02 03 06 07 640x400 * - * - * * Authors: Fred N. van Kempen, * Miran Grca, * John Elliott, diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index c63bfc70a..ef48207e1 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -8,8 +8,6 @@ * * C&T 69000 emulation. * - * - * * Authors: Cacodemon345 * * Copyright 2023-2024 Cacodemon345 diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 0a43ab4ce..abdde1622 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -9,8 +9,6 @@ * Emulation of select Cirrus Logic cards (CL-GD 5428, * CL-GD 5429, CL-GD 5430, CL-GD 5434 and CL-GD 5436 are supported). * - * - * * Authors: Miran Grca, * tonioni, * TheCollector1995, @@ -4339,7 +4337,7 @@ gd54xx_init(const device_t *info) case CIRRUS_ID_CLGD5436: if ((info->local & 0x200) && - !strstr(machine_get_internal_name(), "sb486pv")) { + (machines[machine].init != machine_at_sb486pv_init)) { romfn = NULL; gd54xx->has_bios = 0; } else diff --git a/src/video/vid_ddc.c b/src/video/vid_ddc.c index ba6ac2a6d..dd1bdc0a1 100644 --- a/src/video/vid_ddc.c +++ b/src/video/vid_ddc.c @@ -8,8 +8,6 @@ * * DDC monitor emulation. * - * - * * Authors: RichardG, * * Copyright 2020 RichardG. diff --git a/src/video/vid_ddc_edid_custom.c b/src/video/vid_ddc_edid_custom.c index 2febde67e..4442fac10 100644 --- a/src/video/vid_ddc_edid_custom.c +++ b/src/video/vid_ddc_edid_custom.c @@ -8,15 +8,12 @@ * * Custom monitor EDID file loader. * - * - * * Authors: Cacodemon345, * David Hrdlička, * * Copyright 2025 Cacodemon. * Copyright 2025 David Hrdlička. */ - #include #include #include diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index d25861681..61df063ba 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -9,8 +9,6 @@ * Emulation of the EGA and Chips & Technologies SuperEGA * graphics cards. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_ega_render.c b/src/video/vid_ega_render.c index c1c44dfdb..1c1c0161e 100644 --- a/src/video/vid_ega_render.c +++ b/src/video/vid_ega_render.c @@ -8,8 +8,6 @@ * * EGA renderers. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_et3000.c b/src/video/vid_et3000.c index a75a63829..d86d25363 100644 --- a/src/video/vid_et3000.c +++ b/src/video/vid_et3000.c @@ -8,8 +8,6 @@ * * Emulation of the Tseng Labs ET3000. * - * - * * Authors: Miran Grca, * * Copyright 2016-2018 Miran Grca. diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index b19aad20a..1a8a767e2 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -8,8 +8,6 @@ * * Emulation of the Tseng Labs ET4000. * - * - * * Authors: Fred N. van Kempen, * Miran Grca, * GreatPsycho, diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index 181c3a833..05de0dbea 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -10,8 +10,6 @@ * * Known bugs: Accelerator doesn't work in planar modes * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_genius.c b/src/video/vid_genius.c index 366fa25e1..472217d30 100644 --- a/src/video/vid_genius.c +++ b/src/video/vid_genius.c @@ -8,8 +8,6 @@ * * MDSI Genius VHR emulation. * - * - * * Authors: John Elliott, * Miran Grca, * diff --git a/src/video/vid_hercules.c b/src/video/vid_hercules.c index 15b9e69cd..758b041af 100644 --- a/src/video/vid_hercules.c +++ b/src/video/vid_hercules.c @@ -8,8 +8,6 @@ * * Hercules emulation. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_hercules_incolor.c b/src/video/vid_hercules_incolor.c index 6e3b6a6d2..b9be0765e 100644 --- a/src/video/vid_hercules_incolor.c +++ b/src/video/vid_hercules_incolor.c @@ -8,8 +8,6 @@ * * Hercules InColor emulation. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_hercules_plus.c b/src/video/vid_hercules_plus.c index c6b442ce0..25b44ad70 100644 --- a/src/video/vid_hercules_plus.c +++ b/src/video/vid_hercules_plus.c @@ -8,8 +8,6 @@ * * Hercules Plus emulation. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_ht216.c b/src/video/vid_ht216.c index 3ba814870..005cc6dfa 100644 --- a/src/video/vid_ht216.c +++ b/src/video/vid_ht216.c @@ -8,8 +8,6 @@ * * Video 7 VGA 1024i emulation. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_im1024.c b/src/video/vid_im1024.c index a77ad09c3..1ade8badb 100644 --- a/src/video/vid_im1024.c +++ b/src/video/vid_im1024.c @@ -38,8 +38,6 @@ * This is implemented by holding a FIFO of unlimited depth in * the IM1024 to receive the data. * - * - * * Authors: Fred N. van Kempen, * John Elliott, * diff --git a/src/video/vid_mda.c b/src/video/vid_mda.c index 184ad7fdd..f530419f2 100644 --- a/src/video/vid_mda.c +++ b/src/video/vid_mda.c @@ -8,8 +8,6 @@ * * IBM Monochrome Display and Printer Adapter emulation. * - * - * * Authors: Sarah Walker, * Miran Grca, * Connor Hyde, diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index 564136428..5aadd71f6 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -8,8 +8,6 @@ * * Matrox MGA graphics card emulation. * - * - * * Authors: Sarah Walker, * * Copyright 2008-2020 Sarah Walker. @@ -3753,10 +3751,10 @@ blit_iload_iload(mystique_t *mystique, uint32_t data, int size) case MACCESS_PWIDTH_24: if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { - uint32_t old_dst = *((uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask]); + uint32_t old_dst = AS_U32(svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask]); dst = bitop(data64, old_dst, mystique->dwgreg.dwgctrl_running); - *((uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask]) = (dst & 0xffffff) | (old_dst & 0xff000000); + AS_U32(svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask]) = (dst & 0xffffff) | (old_dst & 0xff000000); svga->changedvram[(((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask) >> 12] = changeframecount; } diff --git a/src/video/vid_oak_oti.c b/src/video/vid_oak_oti.c index 4ea0b21e4..d8e3a89e4 100644 --- a/src/video/vid_oak_oti.c +++ b/src/video/vid_oak_oti.c @@ -8,8 +8,6 @@ * * Oak OTI037C/67/077 emulation. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_paradise.c b/src/video/vid_paradise.c index ff1013232..48796fcc7 100644 --- a/src/video/vid_paradise.c +++ b/src/video/vid_paradise.c @@ -10,8 +10,6 @@ * PC2086, PC3086 use PVGA1A * MegaPC uses W90C11A * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_pcjr.c b/src/video/vid_pcjr.c index 62ce9b61d..fe982980c 100644 --- a/src/video/vid_pcjr.c +++ b/src/video/vid_pcjr.c @@ -8,7 +8,6 @@ * * IBM PCjr video subsystem emulation * - * * Authors: Sarah Walker, * Miran Grca, * Connor Hyde / starfrost @@ -18,7 +17,6 @@ * Copyright 2017-2019 Fred N. van Kempen. * Copyright 2025 starfrost */ - #include #include #include diff --git a/src/video/vid_pgc.c b/src/video/vid_pgc.c index 63126955c..73fde302d 100644 --- a/src/video/vid_pgc.c +++ b/src/video/vid_pgc.c @@ -44,8 +44,6 @@ * * This is expected to be done shortly. * - * - * * Authors: Fred N. van Kempen, * John Elliott, * diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 938e4bf6b..a97d2aa84 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -22,7 +22,6 @@ * * Copyright 2024-2025 Akamaki. */ - #include #include #include @@ -96,20 +95,20 @@ #define DA2_POSID_L 0xfe /* [Identification] - POS ID SYS ID - EFFFh * Display Adapter (PS/55 Model 5571-S0A) [Toledo] - E013h * Layout Display Terminal (PS/55-5571 RPQ model) [LDT] - EFFEh * Display Adapter II (I/O 3E0:0A = xx0x xxxx) [Atlas] - |- FFF2h Display Adapter B2 (I/O 3E0:0A = xx1x xxxx) (PS/55 Model 5530Z-SX) - |- FDFEh Display Adapter B2 (I/O 3E0:0A = xx1x xxxx) (PS/55 Model 5550-V2) - |- * Display Adapter III,V (I/O 3E0:0A = xx1x xxxx) - ECECh FF4Fh Display Adapter B1 (PS/55 Model 5531Z-SX) [Atlas-KENT] - |- * Display Adapter IV - ECCEh * Display Adapter IV - 901Fh * Display Adapter A2 - 901Dh * Display Adapter A1 [Atlas II] - 901Eh * Plasma Display Adapter - EFD8h * Display Adapter/J [Atlas-SP2] + POS ID SYS ID + EFFFh * Display Adapter (PS/55 Model 5571-S0A) [Toledo] + E013h * Layout Display Terminal (PS/55-5571 RPQ model) [LDT] + EFFEh * Display Adapter II (I/O 3E0:0A = xx0x xxxx) [Atlas] + |- FFF2h Display Adapter B2 (I/O 3E0:0A = xx1x xxxx) (PS/55 Model 5530Z-SX) + |- FDFEh Display Adapter B2 (I/O 3E0:0A = xx1x xxxx) (PS/55 Model 5550-V2) + |- * Display Adapter III,V (I/O 3E0:0A = xx1x xxxx) + ECECh FF4Fh Display Adapter B1 (PS/55 Model 5531Z-SX) [Atlas-KENT] + |- * Display Adapter IV + ECCEh * Display Adapter IV + 901Fh * Display Adapter A2 + 901Dh * Display Adapter A1 [Atlas II] + 901Eh * Plasma Display Adapter + EFD8h * Display Adapter/J [Atlas-SP2] [Japanese DOS and Display Adapter compatibility] | | | 5605JBK | 5605PAA | 5605PCA | 5605PDE | 5605PAW | 5605PXB | diff --git a/src/video/vid_rtg310x.c b/src/video/vid_rtg310x.c index 813d30bf3..76b8d8f3f 100644 --- a/src/video/vid_rtg310x.c +++ b/src/video/vid_rtg310x.c @@ -8,8 +8,6 @@ * * Emulation of the Realtek RTG series of VGA ISA chips. * - * - * * Authors: TheCollector1995, * * Copyright 2021 TheCollector1995. diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index e3176381a..2333d68b7 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -8,8 +8,6 @@ * * S3 emulation. * - * - * * Authors: Sarah Walker, * Miran Grca, * @@ -530,9 +528,8 @@ s3_queue(s3_t *s3, uint32_t addr, uint32_t val, uint32_t type) if (FIFO_FULL) { thread_reset_event(s3->fifo_not_full_event); - if (FIFO_FULL) { + if (FIFO_FULL) thread_wait_event(s3->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ - } } fifo->val = val; diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index d8356df4a..d9e1d91ef 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -8,8 +8,6 @@ * * S3 ViRGE emulation. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_sigma.c b/src/video/vid_sigma.c index 9f71773ad..4759bb7af 100644 --- a/src/video/vid_sigma.c +++ b/src/video/vid_sigma.c @@ -8,8 +8,6 @@ * * Sigma Color 400 emulation. * - * - * * Authors: John Elliott, * * Copyright 2018 John Elliott. diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index cbbf98ab4..03f829e74 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -11,8 +11,6 @@ * This is intended to be used by another SVGA driver, * and not as a card in its own right. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index 92228243f..25b3cd946 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -8,8 +8,6 @@ * * SVGA renderers. * - * - * * Authors: Sarah Walker, * Miran Grca, * @@ -157,7 +155,7 @@ svga_render_text_40(svga_t *svga) svga->lastline_draw = svga->displine; if (svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; + p = &svga->monitor->target_buffer->line[(svga->displine + svga->y_add) & 2047][(svga->x_add) & 2047]; xinc = (svga->seqregs[1] & 1) ? 16 : 18; for (int x = 0; x < (svga->hdisp + svga->scrollcache); x += xinc) { @@ -240,7 +238,7 @@ svga_render_text_80(svga_t *svga) svga->lastline_draw = svga->displine; if (svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; + p = &svga->monitor->target_buffer->line[(svga->displine + svga->y_add) & 2047][(svga->x_add) & 2047]; xinc = (svga->seqregs[1] & 1) ? 8 : 9; static uint32_t col = 0x00000000; diff --git a/src/video/vid_table.c b/src/video/vid_table.c index 20a8f311d..4e76e150d 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -8,8 +8,6 @@ * * Define all known video cards. * - * - * * Authors: Miran Grca, * Fred N. van Kempen, * diff --git a/src/video/vid_tandy.c b/src/video/vid_tandy.c index f11b687ef..bca6d6efa 100644 --- a/src/video/vid_tandy.c +++ b/src/video/vid_tandy.c @@ -8,8 +8,6 @@ * * Tandy 1000 video emulation * - * - * * Authors: Sarah Walker, * Miran Grca, * Connor Hyde / starfrost, diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index 6a0e1ca5e..2fd4ba482 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -47,8 +47,6 @@ * access size or host data has any affect, but the Windows 3.1 * driver always reads bytes and write words of 0xffff. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_ti_cf62011.c b/src/video/vid_ti_cf62011.c index fcc046cb4..afea65374 100644 --- a/src/video/vid_ti_cf62011.c +++ b/src/video/vid_ti_cf62011.c @@ -42,8 +42,6 @@ * which are the same as the XGA. It supports up to 1MB of VRAM, * but we lock it down to 512K. The PS/1 2122 had 256K. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, diff --git a/src/video/vid_tvga.c b/src/video/vid_tvga.c index 51ab132ca..0a436178b 100644 --- a/src/video/vid_tvga.c +++ b/src/video/vid_tvga.c @@ -8,8 +8,6 @@ * * Trident TVGA (8900D) emulation. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_vga.c b/src/video/vid_vga.c index 4cde5ba01..1d3db4645 100644 --- a/src/video/vid_vga.c +++ b/src/video/vid_vga.c @@ -8,8 +8,6 @@ * * IBM VGA emulation. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_voodoo.c b/src/video/vid_voodoo.c index 57ddbf64d..fe02b7811 100644 --- a/src/video/vid_voodoo.c +++ b/src/video/vid_voodoo.c @@ -8,8 +8,6 @@ * * Voodoo Graphics, 2, Banshee, 3 emulation. * - * - * * Authors: Sarah Walker, * leilei * diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index 7bd94a34a..abccff860 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -8,8 +8,6 @@ * * Voodoo Banshee and 3 specific emulation. * - * - * * Authors: Sarah Walker, * * Copyright 2008-2020 Sarah Walker. diff --git a/src/video/vid_voodoo_banshee_blitter.c b/src/video/vid_voodoo_banshee_blitter.c index ad92d580f..ac8cb172d 100644 --- a/src/video/vid_voodoo_banshee_blitter.c +++ b/src/video/vid_voodoo_banshee_blitter.c @@ -1,3 +1,17 @@ +/* + * 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. + * + * 3DFX Voodoo emulation. + * + * Authors: Sarah Walker, + * + * Copyright 2008-2020 Sarah Walker. + */ /*Current issues : - missing YUV blits (YUV -> 32-bit, 24-bit, or 16-bit RGB now done) - missing wait for vsync diff --git a/src/video/vid_voodoo_blitter.c b/src/video/vid_voodoo_blitter.c index 6ea2edcc3..0d2c9e103 100644 --- a/src/video/vid_voodoo_blitter.c +++ b/src/video/vid_voodoo_blitter.c @@ -8,8 +8,6 @@ * * 3DFX Voodoo emulation. * - * - * * Authors: Sarah Walker, * * Copyright 2008-2020 Sarah Walker. diff --git a/src/video/vid_voodoo_display.c b/src/video/vid_voodoo_display.c index d04376941..3595d8b89 100644 --- a/src/video/vid_voodoo_display.c +++ b/src/video/vid_voodoo_display.c @@ -8,8 +8,6 @@ * * 3DFX Voodoo emulation. * - * - * * Authors: Sarah Walker, * * Copyright 2008-2020 Sarah Walker. diff --git a/src/video/vid_voodoo_fb.c b/src/video/vid_voodoo_fb.c index ddf68360f..cb5a614d4 100644 --- a/src/video/vid_voodoo_fb.c +++ b/src/video/vid_voodoo_fb.c @@ -8,8 +8,6 @@ * * 3DFX Voodoo emulation. * - * - * * Authors: Sarah Walker, * * Copyright 2008-2020 Sarah Walker. diff --git a/src/video/vid_voodoo_fifo.c b/src/video/vid_voodoo_fifo.c index 83be0f7bb..612ca4c18 100644 --- a/src/video/vid_voodoo_fifo.c +++ b/src/video/vid_voodoo_fifo.c @@ -8,8 +8,6 @@ * * 3DFX Voodoo emulation. * - * - * * Authors: Sarah Walker, * * Copyright 2008-2020 Sarah Walker. diff --git a/src/video/vid_voodoo_reg.c b/src/video/vid_voodoo_reg.c index 82dfde354..38ac42845 100644 --- a/src/video/vid_voodoo_reg.c +++ b/src/video/vid_voodoo_reg.c @@ -8,8 +8,6 @@ * * 3DFX Voodoo emulation. * - * - * * Authors: Sarah Walker, * * Copyright 2008-2020 Sarah Walker. diff --git a/src/video/vid_voodoo_render.c b/src/video/vid_voodoo_render.c index 6bd80ec08..9c1204bd3 100644 --- a/src/video/vid_voodoo_render.c +++ b/src/video/vid_voodoo_render.c @@ -8,8 +8,6 @@ * * 3DFX Voodoo emulation. * - * - * * Authors: Sarah Walker, * * Copyright 2008-2020 Sarah Walker. diff --git a/src/video/vid_voodoo_setup.c b/src/video/vid_voodoo_setup.c index 11f4ff861..d148876eb 100644 --- a/src/video/vid_voodoo_setup.c +++ b/src/video/vid_voodoo_setup.c @@ -8,8 +8,6 @@ * * 3DFX Voodoo emulation. * - * - * * Authors: Sarah Walker, * * Copyright 2008-2020 Sarah Walker. diff --git a/src/video/vid_voodoo_texture.c b/src/video/vid_voodoo_texture.c index f6894ec0f..7651866fd 100644 --- a/src/video/vid_voodoo_texture.c +++ b/src/video/vid_voodoo_texture.c @@ -8,8 +8,6 @@ * * 3DFX Voodoo emulation. * - * - * * Authors: Sarah Walker, * * Copyright 2008-2020 Sarah Walker. diff --git a/src/video/vid_wy700.c b/src/video/vid_wy700.c index c00541113..bd9ba9386 100644 --- a/src/video/vid_wy700.c +++ b/src/video/vid_wy700.c @@ -8,8 +8,6 @@ * * Wyse-700 emulation. * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/video/vid_xga.c b/src/video/vid_xga.c index 8de29a2e6..0a9822006 100644 --- a/src/video/vid_xga.c +++ b/src/video/vid_xga.c @@ -8,8 +8,6 @@ * * IBM XGA emulation. * - * - * * Authors: TheCollector1995. * * Copyright 2022 TheCollector1995. @@ -2718,15 +2716,15 @@ xga_hwcursor_draw(svga_t *svga, int displine) if (x >= idx) { switch (comb) { case 0x00: - /* Cursor Color 1 */ + /* Cursor Color 1 */ p[x_pos] = xga->hwc_color0; break; case 0x01: - /* Cursor Color 2 */ + /* Cursor Color 2 */ p[x_pos] = xga->hwc_color1; break; case 0x03: - /* Complement */ + /* Complement */ p[x_pos] ^= 0xffffff; break; diff --git a/src/video/video.c b/src/video/video.c index e2f2801d3..859794142 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -40,8 +40,6 @@ * W = 3 bus clocks * L = 4 bus clocks * - * - * * Authors: Sarah Walker, * Miran Grca, * diff --git a/src/vnc.c b/src/vnc.c index cd9911b02..d440aa21b 100644 --- a/src/vnc.c +++ b/src/vnc.c @@ -8,8 +8,6 @@ * * Implement the VNC remote renderer with LibVNCServer. * - * - * * Authors: Fred N. van Kempen, * Based on raw code by RichardG, * diff --git a/src/vnc_keymap.c b/src/vnc_keymap.c index 599ba1d9b..b801546c2 100644 --- a/src/vnc_keymap.c +++ b/src/vnc_keymap.c @@ -22,8 +22,6 @@ * NOTE: The values are as defined in the Microsoft document named * "Keyboard Scan Code Specification", version 1.3a of 2000/03/16. * - * - * * Authors: Fred N. van Kempen, * Based on raw code by RichardG, *