Compare commits

..

50 Commits

Author SHA1 Message Date
icex2
649e031712 wip workflows 2023-04-10 23:23:08 +02:00
icex2
64901bdb61 chore: Bump version to 5.45 to start next development cycle 2023-04-06 15:56:31 +02:00
icex2
52ff4927b4 chore: Update changelog for 5.44 release 2023-04-06 15:39:53 +02:00
icex2
d989e75488 feat(doc iidx15): Add crashinig on boot due to no backup data 2023-04-06 15:39:53 +02:00
icex2
b0564b97c6 chore: Apply code formatting to entire code base 2023-04-06 15:39:53 +02:00
icex2
47bfb4e9b2 chore(doc): Add dev journal about 10th style IO and security boot 2023-04-06 15:39:53 +02:00
icex2
5c4afb8a2a fix(iidx/config): Utilize io board type, fix 10th SQ-INIT error
Using the right combination of "flags", this addresses the
SQ-INIT error on 10th style as well as forces 10 to 13 into
using the D01 operation mode. The latter follows the approach that
14+ is also using the best/latest IO type supported (IO2 in that
case). Expecting that gameplay experience benefits from more
optimized/better maintained code paths.

Make 10 operate in D01 IO mode which forces security to using
the D01 dongle from a D01 dedicab setup. The alternative would
be using a C02 dongle from a C02 upgraded cabinet.

More details to follow in another commit with a dev journal
entry.
2023-04-06 15:39:53 +02:00
icex2
83ef8e2e9d chore(iidx): Wire-up ezusb configuration in iidxhook1 and 2
Make io board type for ezusb board configurable as well as allow
switching on/off additional ezusb debugging feature.
2023-04-06 15:39:53 +02:00
icex2
3a71a5047a feat(iidx/config): Expose ezusb specific configuration params
Useful (debugging) and required (io board type) for different
game versions
2023-04-06 15:39:53 +02:00
icex2
aaab9bfbfc feat(iidx/ezusb): Make iidx ezusb emu io board type configurable
Second part to fixing the 10th style SQ-INIT error. This has
cross-impact on the kind of security data the game expects.
Therefore, we need to expose the IO board type and make it
configurable like the security data for the different game
versions.

More details explained in a dev journal entry to following
in one of the next commits.
2023-04-06 15:39:53 +02:00
icex2
eab80455b2 fix(iidx/ezusb): ezusb does not have a white dongle
This is one part of fixing the 10th style SQ-INIT boot error.
For some reason, 10th style calls the "second dongle slot"
which, according to the code, is expected to return the same data
as the first (black) dongle slot. Original ezusb/C02/D01 IO boards
do not have a second dongle round plug slot nor ever came with
a splitter cable. I checked original manuals of the C02 conversion
kit, E11 and ECO software upgrade kits. No white dongle nor
additional hardware for any other dongle than a black dongle.
2023-04-06 15:39:53 +02:00
icex2
27e9775101 fix(iidx/ezusb2): Fix IO buffer inconsistency on ezusb ioctl level
See same commit for ezusb for details and reasoning.
2023-04-06 15:39:53 +02:00
icex2
da94ad8f76 fix(iidx/ezusb): Fix IO buffer inconsistency on ezusb ioctl level 2023-04-06 15:39:53 +02:00
icex2
4c127d26e5 chore(dev): Fix incorrect log module header 2023-04-06 15:39:53 +02:00
icex2
e807376d6b feat(iidx/ezusb): Add ezusb api monitoring module
Implement several functions relevant to the boot process with
a focus on the security init part
2023-04-06 15:39:53 +02:00
icex2
a2c2d31ca8 fix(iidx/ezusb2): Fix IO buffer inconsistency on ezusb device level 2023-04-06 15:39:53 +02:00
icex2
22978afc9b feat(iidx 14-24): Wire up coin mech to IO emulation 2023-04-06 15:39:53 +02:00
icex2
94c562f17b feat(iidx 9-13): Wire up coin mech to IO emulation 2023-04-06 15:39:53 +02:00
icex2
1f95437b17 fix(pnm/ezusb2-emu): Fix IO buffer inconsistency/random input misfiring 2023-04-06 15:39:53 +02:00
icex2
58d4130c2a fix(jb/p4io): Fix IO buffer inconsistency/random input misfiring 2023-04-06 15:39:53 +02:00
icex2
e530968dab fix(jb/p3io): Fix IO buffer inconsistency/random input misfiring 2023-04-06 15:39:53 +02:00
icex2
99d756f207 fix(iidx/ezusb2): Fix IO buffer inconsistency/random input misfiring 2023-04-06 15:39:53 +02:00
icex2
2b8d19d82a chore: Move and convert from gitlab templates to github templates 2023-04-06 15:39:53 +02:00
icex2
fb84085f69 chore(doc): Re-structure, separate dev journals 2023-04-06 15:39:53 +02:00
icex2
ffe678de61 feat(iidx19): imagefs override strategy with local file redir 2023-04-06 15:39:53 +02:00
icex2
031836ef0e chore: Apply code formatting on entire codebase for consistent style 2023-04-06 15:39:53 +02:00
icex2
a1a849aef3 feat(iidx18/19): Improve chart-patch to correctly support iidx 18 and 19
The paths changed for 18 and again for 19. Refactor and improve
the detection logic to consider this. This also should make
the code more maintainable.
2023-04-06 15:39:53 +02:00
icex2
32c786de27 fix(iidxhook-util/chart-patch): Bugfix broken synchronization
The synchronization block was too coarse and kept the lock
acquired even when the hooked call continued traversing because
it skipped the chart patch trap code. This was apparently fine
on several games but caused very flaky deadlocking on iidx18
during the boot screens and even crashed iidx19 consistently
before showing the boot screen.
2023-04-06 15:39:53 +02:00
icex2
4d9fe0002a fix(iidxhook-util/settings): Bugfix broken paths with mixed / and \
Applies to iidx18 and iidx19 when using the recently extended
redirect feature for settings paths, mixing / and \ crashes the
game in some operator sub-menus when trying to save settings.
2023-04-06 15:39:53 +02:00
icex2
a2ceb0f6cc doc: Add documentation about parallel building being broken 2023-04-06 15:39:53 +02:00
icex2
2a57ed9916 fix(dev): Upgrade docker file, move to latest debian bullseye base image
The fedora image was already quite old but also took ages to
initially install the dependencies. Being more familiar with debian,
initial container building with package installation being rather
quick, and assuming most folks being more familiar debian as well,
I decided to shift to make this easier to maintain.
2023-04-06 15:39:53 +02:00
icex2
825ac8e6d2 chore(dev): Fix compiler warning about not knowing the definition for a struct 2023-04-06 15:39:53 +02:00
icex2
ef103eb299 chore(dev): Fix format warning 2023-04-06 15:39:53 +02:00
icex2
65aa31ca22 chore(dev): Fix compiler warning, use correct format for size_t type 2023-04-06 15:39:53 +02:00
icex2
ecda3ff86f fix(iidx/ezusb): Improve code resiliance of ezusb node-serial module
- Use static assert to verify struct sizes
- Replace "magic numbers" with proper sizeof's
- Allocate largest size buffer for message response to address
  compiler warnings which indicates potential out of bounds
  reads/writes
2023-04-06 15:39:53 +02:00
icex2
389708f794 chore(doc): Documentation cleanup and improvements
- Add index with aux tooling to main readme
- Move release process to doc, not valuable to have this on the
  main readme
2023-04-06 15:39:53 +02:00
icex2
34aca9dc2a chore(dev): Disable formatting on some files to prevent header resorting
This leads to compiler errors as windows.h is expected to be
the first header included for other windows related header files.
2023-04-06 15:39:53 +02:00
icex2
c2104e7758 chore(dev): Scope code formatting to src/main and src/test
Do not format imports which includes headers from other projects
with different code styles.
2023-04-06 15:39:53 +02:00
icex2
6a140699ec fix(dev): Improve deps docker build process, mount local folder as volume
This removes the need to copy all the data into the docker container
and outputs from the build process out of the container. In
hindsight, this was a poor design decision as it created docker
images that were very large with data, that you don't have to
keep stored once the build finished, e.g. the build output.

Therefore, mount the local folder, keep the checkouts also local
which is good for debugging and also re-using them to build without
the docker container (no second checkout required).

Build output is also written directly to the build/ output folder

Overall, the docker container is more lightweight and actually
a "build environment" only not tainted with specific versions
of the dependencies to build.
2023-04-06 15:39:53 +02:00
icex2
b2e0d9f3d6 feat(iidx19): Add back btools monitor check for iidxhook5
Provide an option for non final lincle revisions and
if the "modern" monitor check is not delivering stable
results on the final lincle revision, e.g. using the
original "pendual lcd" monitor.
2023-04-06 15:39:53 +02:00
icex2
cb884c307c iidx: Update dist default files, add settings_path item 2023-03-19 21:15:28 +01:00
icex2
1154444d16 iidxhook: Integrate settings hook configurability 2023-03-19 21:15:28 +01:00
icex2
7b90963f53 iidhxook-util: Expose settings_path as a configuration option 2023-03-19 21:15:28 +01:00
icex2
722927caa7 iidxhook-util: Add option to configure path for storing settings
Additional flexibility to cover use-cases like storing this
data on a separate partition which keeps the game data folder
clean and read-only.
2023-03-19 21:15:28 +01:00
icex2
5eb40bfad3 dist/iidx27: Align disabled cam connection with 28 and 29
The default should be targeting emulation on a "normal
desktop pc". The default confits for 28 and 29 refeclt
that already, but it seems that 27 was missed out here.
2023-03-06 00:08:06 +01:00
icex2
f2678539c3 Bugfix inject: Handle process exit event correctly
When the process requests to exit, the debugger thread attached
from inject swallowed that event simply without taking action
of actually terminating the process. Handle this accordingly
when the debugger loop is running and terminate the process
2023-03-06 00:08:06 +01:00
icex2
bb0d2823bf Bugfix util/proc: Forward exit code to TerminateProcess 2023-03-06 00:08:06 +01:00
icex2
cb290ab02e Add .DS_Store to .gitignore 2023-03-06 00:08:06 +01:00
1f68cdff2564c6c03bac2fa00ca22e9e02f41e43
3d955a8dca Rewrite batch files, allow passing args, terminal close fix 2022-12-22 19:08:52 +01:00
17cef301cbf0c9bbe9e0c5a946206d54079429d7
4a333d0b13 Fixed gamestart.bat files for Chinese IIDX styles
Chinese IIDX styles will hang if bemanitools can't mount the dev\\nvram and dev\\raw folders. This simply adds commands to their gamestart.bat files to create those directories if they don't exist, preventing the game from hanging.
2022-12-19 23:19:48 +00:00
250 changed files with 4607 additions and 2364 deletions

View File

@@ -1,17 +1,24 @@
# Bug report
## Summary
<!--- Provide a general summary of the issue in the Title above -->
## Expected behavior
<!--- Tell us what should happen -->
## Current behavior
<!--- Tell us what happens instead of the expected behavior -->
## Detailed Description
<!--- Provide a detailed description of the issue. Include links to screenshots or videos if
necessary -->
## Steps to reproduce
<!-- Try running the game with a default configuration as well. If that also causes issues, please point that out here in the report. This might speed up the debugging process.-->
<!--- Provide a detailed step by step description how to reproduce this issue -->
@@ -21,17 +28,23 @@ necessary -->
4.
## Possible solution
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
## Context (Environment)
### Bemanitools version(s) affected
* <!--- Add one or multiple versions as a bullet list -->
### Game(s) and version(s) affected
* <!--- Add one or multiple game versions as a bullet list -->
### Log output
See attachment.
<!---
Provide FULL log output, e.g. inject.log or launcher.log. Please do not guess which things
are relevant or not. Without knowing, you might leave out things that are relevant for the developers. You have to enable log output explicitly if not done already.
@@ -50,7 +63,9 @@ Use the search and replace feature of any kind of text editor.
-->
### Configuration files
See attachment.
<!--- Provide any configuration files that you used, e.g. iidxhook-XX.conf. This file is located in
the same directory as launcher.exe or inject.exe.
@@ -66,17 +81,21 @@ Use the search and replace feature of any kind of text editor.
-->
### Command line arguments
<!--- Provide how you run the game from the command line, e.g. which gamestart.bat you used and any
additional arguments that you provided to it. Also provide the contents of the gamestart.bat you
used if you altered it. -->
### APIs used
* <!--- List all APIs you used as a bullet list, e.g. iidxio-keyboard, eamio-keyboard -->
### OS version
<!--- Provide the version of Windows you used with whatever update/build identifier -->
### Hardware specs
* CPU: <!--- Insert, e.g. Core i7 2600k 3.20ghz -->
* RAM: <!--- Insert, e.g. 16 GB -->
* GPU: <!--- Insert, e.g. Nvidia GeForce GTX 970, 4GB -->

View File

@@ -1,14 +1,21 @@
# Feature request
## Summary
<!--- Provide a general summary of your changes in the Title above -->
## Detailed description
<!--- Describe your feature in detail -->
## Benefits
<!--- Describe the value/benefits of the feature in detail -->
## Drawbacks
<!--- Describe any drawbacks that might be introduced with this feature -->
## Current blockers
<!--- Describe any blockers that need to be resolved before implementing this feature -->

View File

@@ -1,23 +1,31 @@
# Pull request
## Summary
<!--- Provide a general summary of your changes in the Title above -->
## Description
<!--- Describe your changes in detail -->
## Related Issue
<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->
## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
## Checklist
<!-- Make sure you covered all items, which apply, of the checklist below. -->
<!-- Strikethrough items that do not apply and provide a brief description why. -->
* [ ] Implemented (unit) test(s) which prove that the introduced changes are working as expected.
* Tested with the following games:
* [ ] ... <!-- insert game name 1-->

38
.github/workflows/build-master.yaml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: "Build bemanitools"
on:
push:
branches:
- master
jobs:
build:
runs-on: "ubuntu-22.04"
steps:
- name: "Checkout repository"
uses: "actions/checkout@v2"
- name: "Install prerequisites"
run: |
sudo apt-get update
sudo apt-get install -y runc containerd docker.io
- name: "Build"
run: |
make build-docker
# Do some unpacking of the dist zip. Artifact upload repackages stuff
- name: "Prepare artifact package"
run: |
mkdir artifact
cd artifact
unzip ../build/bemanitools.zip
cd ..
- name: "Upload artifact"
uses: "actions/upload-artifact@v2"
with:
name: bemanitools-${{ github.sha }}
retention-days: 30
if-no-files-found: "error"
path: |
artifact/**

71
.github/workflows/build-tag.yaml vendored Normal file
View File

@@ -0,0 +1,71 @@
name: "Build bemanitools"
on:
push:
tags:
- "*.*"
jobs:
build:
runs-on: "ubuntu-22.04"
steps:
- name: "Checkout repository"
uses: "actions/checkout@v2"
# Building bootstrapped using docker containers
- name: "Install prerequisites"
run: |
sudo apt-get update
sudo apt-get install -y runc containerd docker.io
- name: "Build"
run: |
make build-docker
# Do some unpacking of the dist zip. Artifact upload repackages stuff
- name: "Prepare artifact package"
run: |
mkdir artifact
cd artifact
unzip ../build/bemanitools.zip
cd ..
- name: "Upload artifact"
uses: "actions/upload-artifact@v2"
with:
name: bemanitools-${{ github.sha }}
retention-days: 30
if-no-files-found: "error"
path: |
artifact/**
publish-release:
needs: "build"
runs-on: "ubuntu-22.04"
steps:
# This already extracts the contents of the artifact
- name: "Download artifact"
uses: "actions/download-artifact@v2"
with:
name: bemanitools-${{ github.sha }}
- name: "Get the version"
id: get_version
run: |
echo ::set-output name=VERSION::$(echo $GITHUB_REF | cut -d / -f 3)
# The publish release action does not package the artifact *sigh*
- name: "Create release package"
run: |
zip bemanitools-${{ steps.get_version.outputs.VERSION }}.zip *
- name: "Publish release"
uses: "marvinpinto/action-automatic-releases@v1.2.1"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: "latest"
draft: false
prerelease: true
title: ${{ steps.get_version.outputs.VERSION }}
files: |
bemanitools-${{ steps.get_version.outputs.VERSION }}.zip

3
.gitignore vendored
View File

@@ -3,4 +3,5 @@ build/
.idea
.vscode
.vs
version
version
.DS_Store

View File

@@ -1,27 +0,0 @@
## Summary
<!--- Provide a general summary of your changes in the Title above -->
## Description
<!--- Describe your changes in detail -->
## Related Issue
<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->
## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
## Checklist
<!-- Make sure you covered all items, which apply, of the checklist below. -->
<!-- Strikethrough items that do not apply and provide a brief description why. -->
* [ ] Implemented (unit) test(s) which prove that the introduced changes are working as expected.
* Tested with the following games:
* [ ] ... <!-- insert game name 1-->
* [ ] ... <!-- insert game name 2--->
* [ ] Followed the developer (style) guidelines.
* [ ] Updated existing doc of or add new doc to README file(s).
* [ ] Updated development documentation.

View File

@@ -2,6 +2,35 @@
Note for CI/CD: Ensure the version formatting in the sections is kept identical to the versions
given in tags. The pipeline will pick this up and cuts out the relevant section for release notes.
## 5.45
### Features
### Fixes
## 5.44
### Features
* feat(doc): ezusb dev journal entry, 10th style ezusb boot up and security setup
* feat(iidx 09/10): ezusb API call monitoring module and configuration flag
* feat(iidx 19): Add back btools monitor check for iidxhook5
* feat(iidx 9-19): Add configurable settings path hook. Redirect settings paths, i.e. `d/`, `e/` and
`f/` drive "folders" to an arbitrary path on any partition, e.g. writable partition
* feat(iidx 9/10): Improve commandline script for irbeat-patch 09 and 10, add interactive mode
### Fixes
* fix(iidx 10): SQ-INIT error caused by incorrect security configuration
* fix(iidx 9-24): Wire up coin input in ezusb1/2 IO emulation layer
* fix(pnm 15-18): Fix IO buffer inconsistency causing random input misfiring
* fix(jb 1-8): Fix IO buffer inconsistency causing random input misfiring
* fix(iidx 9-24): Fix IO buffer inconsistency causing random input misfiring
* fix(iidx 19): imagefs override strategy with local file redir. Required to enable monitor-check
on all chart files
* fix(iidx 9-19): Code synchronization issue causing deadlock resulting in game hang/stuck on boot
* fix(iidx 9-19): Fix broken settings path handling with mixed / and \
* fix(iidx 27): Align disabled cam connection config defaults with 28/29
* fix(inject): Fix missing forwarding of exit code
* fix(inject): Getting stuck when game exits cleanly due to locked up debugger thread.
* fix(iidx 18/19 CN): gamestart.bat creating dev/nvram and dev/raw folders
## 5.43
* iidx29: (Officially) support IIDX CASTHOUR
* Code structure maintenance

View File

@@ -1,32 +1,21 @@
FROM fedora:31
FROM --platform=amd64 debian:11.6-slim@sha256:f7d141c1ec6af549958a7a2543365a7829c2cdc4476308ec2e182f8a7c59b519
LABEL description="Build environment for bemanitools"
RUN yum -y install \
git \
# mingw-w64-gcc has 32-bit and 64-bit toolchains
RUN apt-get update && apt-get install -y --no-install-recommends \
mingw-w64 \
mingw-w64-common \
make \
zip \
clang \
mingw64-gcc.x86_64 \
mingw32-gcc.x86_64 \
wine.x86_64
git \
&& rm -rf /var/lib/apt/lists/*
RUN mkdir /bemanitools
WORKDIR /bemanitools
# Order optimized for docker layer caching
COPY run-tests-wine.sh run-tests-wine.sh
COPY CHANGELOG.md CHANGELOG.md
COPY CONTRIBUTING.md CONTRIBUTING.md
COPY LICENSE LICENSE
COPY GNUmakefile GNUmakefile
COPY Module.mk Module.mk
COPY README.md README.md
COPY doc doc
COPY dist dist
COPY src src
# .git folder required or building fails when version is generated
COPY .git .git
# Building
RUN make
ENTRYPOINT [ \
"/bin/sh", \
"-c" , \
"cd /bemanitools && \
make" ]

View File

@@ -14,7 +14,7 @@ BUILDDIR ?= build
builddir_docker := $(BUILDDIR)/docker
docker_container_name := "bemanitools-build"
docker_image_name := "bemanitools:build"
docker_image_name := "bemanitools-build:latest"
depdir := $(BUILDDIR)/dep
objdir := $(BUILDDIR)/obj
@@ -69,7 +69,7 @@ clean:
code-format:
$(V)echo "Applying clang-format..."
$(V)find src/ -name '*.c' -o -name '*.h' | xargs clang-format -i -style=file
$(V)find src/main src/test -name '*.c' -o -name '*.h' | xargs clang-format -i -style=file
run-tests:
$(V)echo "Running tests..."
@@ -81,13 +81,21 @@ version:
build-docker:
$(V)docker rm -f $(docker_container_name) 2> /dev/null || true
$(V)docker build -t $(docker_image_name) -f Dockerfile .
$(V)docker create --name $(docker_container_name) $(docker_image_name)
$(V)rm -rf $(builddir_docker)
$(V)mkdir -p $(builddir_docker)
$(V)docker cp $(docker_container_name):/bemanitools/build $(builddir_docker)
$(V)mv $(builddir_docker)/build/* $(builddir_docker)
$(V)rm -r $(builddir_docker)/build
$(V)docker \
build \
-t $(docker_image_name) \
-f Dockerfile \
.
$(V)docker \
run \
--volume $(shell pwd):/bemanitools \
--name $(docker_container_name) \
$(docker_image_name)
clean-docker:
$(V)docker rm -f $(docker_container_name) || true
$(V)docker image rm -f $(docker_image_name) || true
$(V)rm -rf $(BUILDDIR)
#
# Pull in module definitions

View File

@@ -1,11 +1,11 @@
# Bemanitools 5
[![pipeline status](https://dev.s-ul.net/djhackers/bemanitools/badges/master/pipeline.svg)](https://dev.s-ul.net/djhackers/bemanitools/commits/master)
Version: 5.43
Version: 5.45
[Release history](CHANGELOG.md)
A collection of tools to run [various Bemani arcade games](#list-of-supported-games).
A collection of tools to run [various Bemani arcade games](#supported-games).
Bemanitools 5 (BT5) is the successor to Bemanitools 4 which introduces a big code cleanup and support for newer games.
BT5 uses a cleaner approach than BT4 did; specifically, all input and lighting is handled by emulating the protocols
@@ -85,19 +85,42 @@ The following games are supported with their corresponding hook-libraries.
* SOUND VOLTEX Vivid Wave (`sdvx-05-to-06`): sdvxhook2
* SOUND VOLTEX EXCEED GEAR (`sdvx-05-to-06`): sdvxhook2
## ViGEm clients: Expose BT5 APIs as XBOX game controllers
Play your favorite non-bemani arcade games with any hardware, e.g. real cabinet hardware, that
implements BT5 APIs.
## Auxiliary tooling
* Bootstrapping
* [inject](doc/inject.md): Inject arbitrary hooking libraries into a target application process.
* [launcher](doc/launcher.md): Bootstrap Konami's AVS environment and launch a target application with arbitrary
injected hooking libraries.
* Beatmnia IIDX Ezusb IO board
* [ezusb-iidx-fpga-flash](doc/tools/ezusb-iidx-fpga-flash.md): Flash a binary blob with FPGA firmware to a target
ezusb FX IO board
* [ezusb-iidx-sram-flash](doc/tools/ezusb-iidx-sram-flash.md): Flash a binary blob with SRAM contents to a target
ezusb FX2 IO board
* Exit hooks: Exit the game with a button combination using native cabinet inputs
* [iidx-ezusb-exit-hook](doc/tools/iidx-ezusb-exit-hook.md): For IIDX with ezusb IO
* [iidx-bio2-exit-hook](doc/tools/iidx-bio2-exit-hook.md): For IIDX with BIO2 IO
* [iidx-ezusb2-exit-hook](doc/tools/iidx-ezusb-exit-hook.md): For IIDX with ezusb FX2 IO
* Bemanitools API testing: Tools for testing bemanitools API implementations
* [eamiotest](doc/tools/eamiotest.md): For [eamio API](doc/api.md#eamuse-readers)
* [iidxiotest](doc/tools/iidxiotest.md): For [iidxio API](doc/api.md#io-boards)
* [jbiotest](doc/tools/jbiotest.md): For [jbio API](doc/api.md#io-boards)
* [aciotest](doc/tools/aciotest.md): Command line tool to quickly test ACIO devices
* config: UI input/output configuration tool when using the default bemanitools API (geninput)
* ir-beat-patch-9/10: Patch the IR beat phase on IIDX 9 and 10
* [mempatch-hook](doc/tools/mempatch-hook.md): Patch raw memory locations in the target process based on the provided
configuration
* [pcbidgen](doc/tools/pcbidgen.md): Konami PCBID generator tool
* [ViGEm clients](doc/vigem/README.md): Expose BT5 APIs as XBOX game controllers to play any games with real cabinet
hardware.
See the dedicated [readme](doc/vigem/README.md) for details.
## Pre-requisites
## Supported platforms
### Supported platforms
Our main platforms are currently Windows XP and Windows 7 which are also the target platforms on the original hardware
of those games. However, as it gets more difficult to get and maintain hardware comptible with Windows XP, this might
change in the future. Many games also run on very recent Windows 10 builds but bear with us that it's hard to keep up
with Windows updates breaking legacy software.
## Distribution contents
### Distribution contents
Check the [list of supported games](#supported-games) to grab the right files for your game. BT5 also includes
a *tools* subpackage (tools.zip) as well as the full source code (src.zip).
@@ -105,7 +128,7 @@ You will find *.md files in various sub-packages that give you further instructi
or FAQ. We advice you to read them as your questions and concerns might already be answered by them. If not, let us
know if there is any information that you consider helpful or important to know and should be added.
## Setup and dependencies
### Setup and dependencies
Most (older generation) games were developed for Windows XP Embedded but should run fine on any
consumer version of Windows XP. Newer versions of Windows, e.g. Windows 7, 8 and 10, should be fine
as well. Some hooks also include fixes required to run the games on a more recent version.
@@ -134,32 +157,7 @@ important aspects you should know before you get started with development.
Please refer to the [API documentation](doc/api.md).
## Release process
Steps for the release process:
1. Update the corresponding section in the [changelog](CHANGELOG.md) with bullet points reflecting
major features merged into master since the previous release
1. Make sure you have the latest `master` state pulled to your local copy
1. Tag the release with the next release number which also be found at the
[top of the readme](#bemanitools-5) as it always reflects the current version beinged worked on
on the `master` branch , e.g. 5.35: `git tag 5.35`
1. Push the tag to upstream: `git push origin 5.35`
1. The [build pipeline](https://dev.s-ul.net/djhackers/bemanitools/-/pipelines) should start
automatically once the tag is pushed including the steps `build` and `upload-release`
1. Once completed successfully, the release is uploaded
1. Take the changelog of the published version and notify the pigs in the stall about it:
1. New post in thread
```
<insert version here> released: <direct link to published version>
Changelog:
<paste changelog here>
```
1. Update the OP title by bumping the version number in it
1. Update the OP post by extending it accordingly (see previous entries)
1. Bump the version number at the [top of this readme](#bemanitools-5) and add a new empty section
in the [changelog](CHANGELOG.md) with the new version number as title. Commit changes and push to
`master` branch
1. Continue developing and merging MRs until you decide its time for another release
Please refer to the [dedicated documentation](doc/release-process.md).
## License
Source code license is the Unlicense; you are permitted to do with this as thou wilt. For details, please refer to the

View File

@@ -11,4 +11,7 @@ if not exist e\avs_conf\CONF mkdir e\avs_conf\CONF
if not exist e\avs_conf\CONF\NVRAM mkdir e\avs_conf\CONF\NVRAM
if not exist e\avs_conf\CONF\RAW mkdir e\avs_conf\CONF\RAW
if not exist dev\nvram mkdir dev\nvram
if not exist dev\raw mkdir dev\raw
inject iidxhook4-cn.dll bm2dx.exe -D --config iidxhook-18-cn.conf %*

View File

@@ -11,4 +11,7 @@ if not exist e\avs_conf\CONF mkdir e\avs_conf\CONF
if not exist e\avs_conf\CONF\NVRAM mkdir e\avs_conf\CONF\NVRAM
if not exist e\avs_conf\CONF\RAW mkdir e\avs_conf\CONF\RAW
if not exist dev\nvram mkdir dev\nvram
if not exist dev\raw mkdir dev\raw
inject iidxhook5-cn.dll bm2dx.exe -D --config iidxhook-20-cn.conf %*

View File

@@ -1,12 +1,45 @@
@echo off
cd /d %~dp0
IF "%1"=="" GOTO USAGE
REM Open menu if no arguments specified
if "%~1" == "" goto menu
iidx-irbeat-patch.exe 9 %1 e\\settings.bin.0
iidx-irbeat-patch.exe 9 %1 f\\settings.bin.1
GOTO END
if "%~1" gtr "3" goto badbeat
if "%~1" == "0" goto badbeat
:USAGE
ECHO "Usage: iidx-irbeat-patch.bat <beat phase>"
set beat = "%~1" - 1
iidx-irbeat-patch.exe 9 %beat% e\\settings.bin.0
iidx-irbeat-patch.exe 9 %beat% f\\settings.bin.1
if not errorlevel 0 goto error
echo Beat phase patched sucessfully
exit /b
:menu
echo Select beat phase:
echo 1 - beat#1
echo 2 - beat#2
echo 3 - beat#3
choice /n /c:123
set /a beat = %errorlevel% - 1
echo.
iidx-irbeat-patch.exe 9 %beat% e\\settings.bin.0
iidx-irbeat-patch.exe 9 %beat% f\\settings.bin.1
echo.
if not errorlevel 0 goto error
echo Beat phase patched sucessfully
timeout 5
exit /b
:error
echo Something has gone wrong with the patching process, have you run the game at least once?
pause
exit /b
:badbeat
echo Invalid beat phase specified, values are 1 to 3.
exit /b
:END

View File

@@ -1,12 +1,45 @@
@echo off
cd /d %~dp0
IF "%1"=="" GOTO USAGE
REM Open menu if no arguments specified
if "%~1" == "" goto menu
iidx-irbeat-patch.exe 10 %1 e\\settings.bin.0
iidx-irbeat-patch.exe 10 %1 f\\settings.bin.1
GOTO END
if %~1 gtr 3 goto badbeat
if %~1 == 0 goto badbeat
:USAGE
ECHO "Usage: iidx-irbeat-patch.bat <beat phase>"
set /a beat = %~1 - 1
iidx-irbeat-patch.exe 9 %beat% e\\settings.bin.0
iidx-irbeat-patch.exe 9 %beat% f\\settings.bin.1
if not errorlevel 0 goto error
echo Beat phase patched sucessfully
exit /b
:menu
echo Select beat phase:
echo 1 - beat#1
echo 2 - beat#2
echo 3 - beat#3
choice /n /c:123
set /a beat = %errorlevel% - 1
echo.
iidx-irbeat-patch.exe 10 %beat% e\\settings.bin.0
iidx-irbeat-patch.exe 10 %beat% f\\settings.bin.1
echo.
if not errorlevel 0 goto error
echo Beat phase patched sucessfully
timeout 5
exit /b
:error
echo Something has gone wrong with the patching process, have you run the game at least once?
pause
exit /b
:badbeat
echo Invalid beat phase specified, values are 1 to 3.
exit /b
:END

View File

@@ -46,17 +46,26 @@ gfx.forced_refresh_rate=-1
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1
# Enable monitoring of ezusb.dll calls by logging call traces. Only works on 9th and 10th style!
ezusb.api_call_monitoring=false
# Set the type of ezusb IO board. 0 = C02, 1 = D01. Note: Impacts security settings!
ezusb.io_board_type=0
# Disable operator clock setting system clock time
misc.disable_clock_set=false
# Stub calls to rteffect.dll (10th to DistorteD)
misc.rteffect_stub=false
# Path to store the settings, e.g. bookkeeping, operator settings. d:, e: and f: drive configuration/settings data
misc.settings_path=.\
# Security boot version (e.g. GEC02).
sec.boot_version=GEC02
# Security boot seeds for ezusb, format: X:X:X where X is a number of 0-9 (e.g. 0:0:0).
sec.boot_seeds=0:0:0
# Security black plug mcode id string (e.g. GQC02JAA).
sec.black_plug_mcode=GQC02JAA
# Security black plug mcode id string (e.g. GEC02JAA).
sec.black_plug_mcode=GEC02JAA

View File

@@ -46,12 +46,21 @@ gfx.forced_refresh_rate=-1
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1
# Enable monitoring of ezusb.dll calls by logging call traces. Only works on 9th and 10th style!
ezusb.api_call_monitoring=false
# Set the type of ezusb IO board. 0 = C02, 1 = D01. Note: Impacts security settings!
ezusb.io_board_type=1
# Disable operator clock setting system clock time
misc.disable_clock_set=false
# Stub calls to rteffect.dll (10th to DistorteD)
misc.rteffect_stub=false
# Path to store the settings, e.g. bookkeeping, operator settings. d:, e: and f: drive configuration/settings data
misc.settings_path=.\
# Security boot version (e.g. GEC02).
sec.boot_version=GEC02

View File

@@ -46,12 +46,21 @@ gfx.forced_refresh_rate=-1
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1
# Enable monitoring of ezusb.dll calls by logging call traces. Only works on 9th and 10th style!
ezusb.api_call_monitoring=false
# Set the type of ezusb IO board. 0 = C02, 1 = D01. Note: Impacts security settings!
ezusb.io_board_type=1
# Disable operator clock setting system clock time
misc.disable_clock_set=false
# Stub calls to rteffect.dll (10th to DistorteD)
misc.rteffect_stub=false
# Path to store the settings, e.g. bookkeeping, operator settings. d:, e: and f: drive configuration/settings data
misc.settings_path=.\
# Security boot version (e.g. GEC02).
sec.boot_version=GEC02

View File

@@ -46,6 +46,12 @@ gfx.forced_refresh_rate=-1
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1
# Enable monitoring of ezusb.dll calls by logging call traces. Only works on 9th and 10th style!
ezusb.api_call_monitoring=false
# Set the type of ezusb IO board. 0 = C02, 1 = D01. Note: Impacts security settings!
ezusb.io_board_type=1
# Fix broken 3D background on Happy Sky's music select (if appearing completely white)
misc.happy_sky_ms_bg_fix=false
@@ -55,6 +61,9 @@ misc.disable_clock_set=false
# Stub calls to rteffect.dll (10th to DistorteD)
misc.rteffect_stub=false
# Path to store the settings, e.g. bookkeeping, operator settings. d:, e: and f: drive configuration/settings data
misc.settings_path=.\
# Security boot version (e.g. GEC02).
sec.boot_version=GEC02

View File

@@ -46,6 +46,12 @@ gfx.forced_refresh_rate=-1
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1
# Enable monitoring of ezusb.dll calls by logging call traces. Only works on 9th and 10th style!
ezusb.api_call_monitoring=false
# Set the type of ezusb IO board. 0 = C02, 1 = D01. Note: Impacts security settings!
ezusb.io_board_type=1
# Fix broken 3D background on DistorteD's music select (if appearing completely black)
misc.distorted_ms_bg_fix=false
@@ -55,6 +61,9 @@ misc.disable_clock_set=false
# Stub calls to rteffect.dll (10th to DistorteD)
misc.rteffect_stub=false
# Path to store the settings, e.g. bookkeeping, operator settings. d:, e: and f: drive configuration/settings data
misc.settings_path=.\
# Security boot version (e.g. GEC02).
sec.boot_version=GEC02

View File

@@ -46,5 +46,8 @@ gfx.device_adapter=-1
# Disable operator clock setting system clock time
misc.disable_clock_set=false
# Path to store the settings, e.g. bookkeeping, operator settings. d:, e: and f: drive configuration/settings data
misc.settings_path=.\
# Security black plug mcode id string (e.g. GQC02JAA).
sec.black_plug_mcode=GQGLDJAA

View File

@@ -46,5 +46,8 @@ gfx.device_adapter=-1
# Disable operator clock setting system clock time
misc.disable_clock_set=false
# Path to store the settings, e.g. bookkeeping, operator settings. d:, e: and f: drive configuration/settings data
misc.settings_path=.\
# Security black plug mcode id string (e.g. GQC02JAA).
sec.black_plug_mcode=GQHDDJAA

View File

@@ -49,5 +49,8 @@ gfx.device_adapter=-1
# Disable operator clock setting system clock time
misc.disable_clock_set=false
# Path to store the settings, e.g. bookkeeping, operator settings. d:, e: and f: drive configuration/settings data
misc.settings_path=.\
# Security black plug mcode id string (e.g. GQC02JAA).
sec.black_plug_mcode=GQI00JAA

View File

@@ -49,5 +49,8 @@ gfx.device_adapter=-1
# Disable operator clock setting system clock time
misc.disable_clock_set=false
# Path to store the settings, e.g. bookkeeping, operator settings. d:, e: and f: drive configuration/settings data
misc.settings_path=.\
# Security black plug mcode id string (e.g. GQC02JAA).
sec.black_plug_mcode=GCJDJJAA

View File

@@ -46,5 +46,8 @@ gfx.diagonal_tearing_fix=false
# Disable ezusb IO emulation and enable usage of real ezusb1/2 IO hardware
io.disable_io_emu=false
# Path to store the settings, e.g. bookkeeping, operator settings. d:, e: and f: drive configuration/settings data
misc.settings_path=.\
# Security black plug mcode id string (e.g. GQC02JAA).
sec.black_plug_mcode=GKJDZCAA

View File

@@ -44,4 +44,7 @@ gfx.diagonal_tearing_fix=false
io.disable_card_reader_emu=false
# Disable ezusb IO emulation and enable usage of real ezusb1/2 IO hardware
io.disable_io_emu=false
io.disable_io_emu=false
# Path to store the settings, e.g. bookkeeping, operator settings. d:, e: and f: drive configuration/settings data
misc.settings_path=.\

View File

@@ -7,6 +7,9 @@ gfx.framed=false
# Software limit the frame rate of the rendering loop in hz, e.g. 60 or 59.95 (0.0 = no software limit)
gfx.frame_rate_limit=0.0
# Enable/disable software monitor check/auto timebase or set a pre-determined refresh value. -1 disables this feature. 0 enables auto detecting the current refresh rate on startup. Setting any positive value > 0 allows you to set a pre-determined refresh rate (e.g. retrieved from the monitor check on newer IIDX games). Either the auto detected value or pre-determined value is used to patch any chart files in-memory to fix song synchronization issues. Requires constant refresh rate!!!
gfx.monitor_check=-1.000000
# Patch the GPU device ID detection (leave empty to disable), format XXXX:YYYY, two 4 digit hex numbers (vid:pid). Examples: 1002:7146 (RV515, Radeon X1300), 1002:95C5 (RV620 LE, Radeon HD3450)
gfx.pci_id=1002:7146
@@ -41,4 +44,7 @@ gfx.diagonal_tearing_fix=false
io.disable_card_reader_emu=false
# Disable ezusb IO emulation and enable usage of real ezusb1/2 IO hardware
io.disable_io_emu=false
io.disable_io_emu=false
# Path to store the settings, e.g. bookkeeping, operator settings. d:, e: and f: drive configuration/settings data
misc.settings_path=.\

View File

@@ -43,5 +43,8 @@ gfx.diagonal_tearing_fix=false
# Disable ezusb IO emulation and enable usage of real ezusb1/2 IO hardware
io.disable_io_emu=false
# Path to store the settings, e.g. bookkeeping, operator settings. d:, e: and f: drive configuration/settings data
misc.settings_path=.\
# Security black plug mcode id string (e.g. GQC02JAA).
sec.black_plug_mcode=GKJDZCAA

View File

@@ -11,7 +11,7 @@ io.disable_poll_limiter=false
io.lightning_mode=false
# Disable camera connection
io.disable_cams=false
io.disable_cams=true
# Disables the built in file hooks, requiring manual file creation
io.disable_file_hooks=false

View File

@@ -0,0 +1,289 @@
# Beatmania IIDX 10th Style - D01 IO boot code and security init
Date: 2023-04-03
Author: icex2
Documenting decompiled and reverse engineered code snippets from the D01 JAE `bm2dx.exe`. These
helped me figuring out the two different security boot modes the game supports.
In summary, it supports booting with the C02 IO with a C02 black dongle and a D01 IO board with
a D01 dongle. No other combination is valid because they didn't make sense back then. You either
had an upgraded old style/twinkle cabinet to C02 (GEC02) or you bought a new dedicated cabinet
(GQD01). With 10th style supporting the old C02 dongle, it appears that all owners of a C02 cabinet
with IO board and C02 dongle received a free software update/HDD. This might make sense considering
the short life span of C02 and the game being super buggy, especially in earlier/initial revisions.
The game expects the following "configurations" from bemanitools:
* Booting as upgraded C02 with free D01 upgrade
* `sec.boot_version=GEC02 `
* `sec.boot_seeds=0:0:1`
* `sec.black_plug_mcode=GEC02JAA`
* "D01 IO pin" on IO board not active
* Booting as dedicated
* `sec.boot_version=GEC02 `
* `sec.boot_seeds=0:1:1`
* `sec.black_plug_mcode=GQD01JAA`
* "D01 IO pin" on IO board ACTIVE
All the above was derived from reading and understanding the documented code excerpts below.
## io_boot - sub_402700
Called as the first step in the boot statemachine by the "boot" function `sub_40F9C0`.
```c
// sub_402700
int __stdcall io_boot(int a1)
{
DWORD (__stdcall *timeGetTime)(); // esi
int usb_boot_security_res; // ebp
DWORD time_start; // ebx
int io_boot_state; // edi
DWORD now; // esi
BOOL is_d01_boot_mode; // esi
BOOL v7; // esi
int result; // eax
int v9; // [esp+10h] [ebp-2Ch]
int firmware_version; // [esp+14h] [ebp-28h]
int io_pad_read; // [esp+18h] [ebp-24h] BYREF
char v12[32]; // [esp+1Ch] [ebp-20h] BYREF
dword_4D0768 = 0;
strcpy(byte_4D076C, &byte_4D0858);
timeGetTime = ::timeGetTime;
v9 = 0;
usb_boot_security_res = io_pad_read;
time_start = ::timeGetTime();
io_boot_state = 0;
while ( 2 )
{
switch ( io_boot_state )
{
case 0: // "start io", firmware download and wait for reconnect
if ( usbStart(0) )
{
if ( time_exceeded(time_start, 20000) )
set_io_error_type(1, aErrorUsbioStar);// ERROR(USBIO START)
}
else
{
io_boot_state = 1;
}
goto reset_io_boot_state_label;
case 1: // check firmware
firmware_version = usbFirmResult();
if ( firmware_version == 96 )
{
if ( time_exceeded(time_start, 25000) )
set_io_error_type(1, aErrorFm); // ERROR(FM), FM = firmware
}
else
{
io_boot_state = 2;
}
goto reset_io_boot_state_label;
case 2:
if ( !firmware_version )
{
usbMute(1);
time_start = timeGetTime();
now = timeGetTime();
io_input_is_d01_ezusb = 0;
do
{
usbPadRead(&io_pad_read);
if ( (io_pad_read & 0x10) != 0 )
io_input_is_d01_ezusb = 1;
}
while ( !time_exceeded(now, 2000) );
io_boot_state = 3;
reset_io_boot_state_label:
timeGetTime = ::timeGetTime;
if ( io_boot_state != v9 )
{
v9 = io_boot_state;
time_start = ::timeGetTime();
}
continue; // retry
}
if ( firmware_version > 128 )
{
if ( firmware_version == 254 )
{
set_io_error_type(1, aErrorFmTrnsOut);// ERROR(FM TRNS-OUT)
return 1;
}
if ( firmware_version == 255 )
{
set_io_error_type(1, aErrorFmTimeOut);// ERROR(FM TIME-OUT)
return 1;
}
}
else
{
switch ( firmware_version )
{
case 128:
set_io_error_type(1, aErrorFmReadErr);// ERROR(FM READ-ERR)
return 1;
case -113:
set_io_error_type(1, aErrorFmDlErr);// ERROR(FM DL-ERR)
return 1;
case -33:
set_io_error_type(1, aErrorFmCmprReq);// ERROR(FM CMPR-REQ)
return 1;
}
}
UNKNOWN_ERROR_LABEL:
set_io_error_type(1, aErrorUnknown); // ERROR(UNKNOWN)
return 1;
case 3:
if ( io_init_security() )
{
set_io_error_type(1, aErrorSqInit); // ERROR(SQ-INIT)
return 1;
}
io_boot_state = 4;
goto reset_io_boot_state_label;
case 4:
is_d01_boot_mode = io_input_is_d01_ezusb != 0;
if ( !strncmp(black_dongle_mcode, MCODE_GED01, 5u) )
is_d01_boot_mode = 1;
usb_boot_security_res = usbBootSecurity(aGec02, 0, is_d01_boot_mode, 1);
if ( usb_boot_security_res == 96 )
{
if ( time_exceeded(time_start, 20000) )
set_io_error_type(1, aErrorBtSqInit);// ERROR(BT-SQ-INIT)'
}
else
{
io_boot_state = 5;
}
goto reset_io_boot_state_label;
case 5:
if ( usb_boot_security_res )
{
switch ( usb_boot_security_res )
{
case 0xFFFFFE9F:
set_io_error_type(1, aErrorSecurityE);// ERROR(SECURITY EEP)
result = 1;
break;
case 0xFFFFFECF:
case 0xFFFFFEDF:
set_io_error_type(1, aErrorSecurityI);// ERROR(SECURITY ID or EEP)
result = 1;
break;
case 0xFFFFFEEF:
set_io_error_type(1, aErrorSecurityN);// 'ERROR(SECURITY No Match)'
result = 1;
break;
case 0xFFFFFEFF:
io_boot_state = 6;
goto reset_io_boot_state_label;
default:
goto UNKNOWN_ERROR_LABEL;
}
}
else
{
Sleep(0x3E8u);
result = 0;
}
return result;
case 6: // security conversion/upgrading security dongles
v7 = io_input_is_d01_ezusb != 0;
if ( !usbGetSecurityKey(v12) )
{
if ( usbSetupSecurityComplete(v12, 0, v7, 1) )
set_io_error_type(1, aErrorSecurityC);// ERROR(SECURITY CONVERSION FAILED)
return 1;
}
set_io_error_type(1, aErrorSecurityC); // ERROR(SECURITY CONVERSION FAILED)
goto reset_io_boot_state_label;
default:
goto UNKNOWN_ERROR_LABEL;
}
}
}
```
## io_init_security - sub_402BB0
Sub-function of the [io_boot](#io_boot---sub_402700) function.
```c
// sub_402BB0
int io_init_security()
{
int v0; // esi
int v2; // esi
int mcode_mismatch_cnt; // esi
char white_dongle_data_maybe[10]; // [esp+Ch] [ebp-20h] BYREF
usbSecurityInit();
v0 = 0;
while ( usbSecurityInitDone() )
{
if ( v0 > 1200 )
{
set_io_error_type(-1, aNgSi);
return -1;
}
++v0;
Sleep(16u);
}
pcbid = 0;
dword_4D0754 = 0;
word_4D0758 = 0;
while ( usbGetPCBID(&pcbid) )
Sleep(1u);
*(_DWORD *)black_dongle_mcode = 0;
v2 = 0;
*(_DWORD *)&black_dongle_mcode[4] = 0;
while ( usbGetSecurity(black_dongle_mcode) ) // black_dongle_mcode = GQD01JAA
{
if ( v2 > 1200 )
{
set_io_error_type(-1, aNgPd);
return -1;
}
++v2;
Sleep(16u);
}
set_cabinet_type(black_dongle_mcode[6]);
mcode_mismatch_cnt = black_dongle_mcode[0] != 'G';
if ( io_input_is_d01_ezusb || !strncmp(black_dongle_mcode, MCODE_GED01, 5u) )// Path for using the D01 dongle with D01 IO board
{
if ( (unsigned __int8)black_dongle_mcode[2] != (char)MCODE_D01 )
++mcode_mismatch_cnt;
if ( (unsigned __int8)black_dongle_mcode[3] != SBYTE1(MCODE_D01) )
++mcode_mismatch_cnt;
if ( (unsigned __int8)black_dongle_mcode[4] != SBYTE2(MCODE_D01) )
++mcode_mismatch_cnt;
}
else // Path for using the C02 dongle with C02 IO board
{
if ( (unsigned __int8)black_dongle_mcode[2] != MCODE_C02[0] )
++mcode_mismatch_cnt;
if ( (unsigned __int8)black_dongle_mcode[3] != MCODE_C02[1] )
++mcode_mismatch_cnt;
if ( (unsigned __int8)black_dongle_mcode[4] != MCODE_C02[2] )
++mcode_mismatch_cnt;
if ( !usbGetSecurityKey(white_dongle_data_maybe) )
{
black_dongle_mcode[6] = white_dongle_data_maybe[6];
set_cabinet_type(white_dongle_data_maybe[6]);
}
}
if ( black_dongle_mcode[5] != 'J' )
++mcode_mismatch_cnt;
if ( black_dongle_mcode[6] != 'A' && black_dongle_mcode[6] != 'B' && black_dongle_mcode[6] != 'C' )
++mcode_mismatch_cnt;
if ( !mcode_mismatch_cnt )
return 0;
set_io_error_type(-1, aNgSecurity);
return -1;
}
```

View File

@@ -51,6 +51,10 @@ make
All output is located in the *build* folder including the final *bemanitools.zip* package.
Note about using `-j n` option on make: This is currently considered broken/unreliable. Expect to
run into odd issues like randomly changing unresolved dependency errors. If you attempted this,
run a `make clean` before running `make` again.
### Release building
A release build is a clean build including code formatting and testing. This can be executed by running the following
command:

View File

@@ -214,3 +214,12 @@ If one or multiple of these issues apply, use the built in scaling options by se
to scale to. Usually, you want to set this to the monitor's native resolution, e.g.
1920x1080 for full HD. You can play around with a few different filters using
*gfx.scale_back_buffer_filter* which impacts image quality/blurriness on upscaling.
## DJTroopers crashes on boot
The stock game is buggy and cannot create default backup data correctly. This
can be fixed by using existing backup data from a stock drive or by using
the pre-generated backup data for the `e:\` and `f:\` drives provided by
[bemanitools-supplement](https://github.com/djhackersdev/bemanitools-supplement/tree/master/iidx/15#default-backup-data).
Copy those files to your target location that you have configured to store this
data, e.g. local `e\` and `f\` folders or the target `e:\` and `f:\` volumes.

29
doc/release-process.md Normal file
View File

@@ -0,0 +1,29 @@
# Release process
For bemanitools maintainers, steps for the release process:
1. Update the corresponding section in the [changelog](CHANGELOG.md) with bullet points reflecting
major features merged into master since the previous release
1. Make sure you have the latest `master` state pulled to your local copy
1. Tag the release with the next release number which also be found at the
[top of the readme](#bemanitools-5) as it always reflects the current version beinged worked on
on the `master` branch , e.g. 5.35: `git tag 5.35`
1. Push the tag to upstream: `git push origin 5.35`
1. The [build pipeline](https://dev.s-ul.net/djhackers/bemanitools/-/pipelines) should start
automatically once the tag is pushed including the steps `build` and `upload-release`
1. Once completed successfully, the release is uploaded
1. Take the changelog of the published version and notify the pigs in the stall about it:
1. New post in thread
```
<insert version here> released: <direct link to published version>
Changelog:
<paste changelog here>
```
1. Update the OP title by bumping the version number in it
1. Update the OP post by extending it accordingly (see previous entries)
1. Bump the version number at the [top of this readme](#bemanitools-5) and add a new empty section
in the [changelog](CHANGELOG.md) with the new version number as title. Commit changes and push to
`master` branch
1. Continue developing and merging MRs until you decide its time for another release

View File

@@ -231,6 +231,7 @@ void property_node_datasize(struct property_node *node);
bool std_getenv(const char *key, char *val, uint32_t nbytes);
void std_setenv(const char *key, const char *val);
void* avs_fs_open(const char* path, int mode, int flags);
int avs_fs_addfs(void *filesys_struct);
int avs_fs_mount(
const char *mountpoint, const char *fsroot, const char *fstype, void *data);

View File

@@ -2,6 +2,7 @@ LIBRARY libavs-win32
EXPORTS
avs_boot @237 NONAME
avs_fs_open @178 NONAME
avs_net_ctrl @15 NONAME
avs_shutdown @333 NONAME
avs_thread_create @183 NONAME
@@ -25,4 +26,4 @@ EXPORTS
property_read_query_memsize @100 NONAME
property_search @244 NONAME
std_getenv @226 NONAME
std_setenv @114 NONAME
std_setenv @114 NONAME

View File

@@ -8,8 +8,8 @@
#define AC_IO_CMD_PANB_START_AUTO_INPUT 0x0115
#define AC_IO_PANB_NUM_NODES 4
#define AC_IO_PANB_MAX_KEYS (7*AC_IO_PANB_NUM_NODES)
#define AC_IO_PANB_MAX_KEYPAIRS (AC_IO_PANB_MAX_KEYS/2)
#define AC_IO_PANB_MAX_KEYS (7 * AC_IO_PANB_NUM_NODES)
#define AC_IO_PANB_MAX_KEYPAIRS (AC_IO_PANB_MAX_KEYS / 2)
struct ac_io_panb_keypair {
uint8_t key2 : 4;
@@ -38,5 +38,4 @@ struct ac_io_panb_poll_out {
};
#pragma pack(pop)
#endif

View File

@@ -5,8 +5,8 @@
#include "aciodrv/device.h"
#include "aciodrv/panb.h"
#include "util/thread.h"
#include "util/log.h"
#include "util/thread.h"
static int auto_poll_proc(void *auto_poll_param);
static int auto_poll_threadid;
@@ -17,59 +17,60 @@ static struct ac_io_panb_keypair _keypair[AC_IO_PANB_MAX_KEYPAIRS];
static CRITICAL_SECTION auto_poll_stop_lock;
static bool auto_poll_stop;
static int auto_poll_proc(void * param)
{
struct aciodrv_device_ctx * device = (struct aciodrv_device_ctx *) param;
static int auto_poll_proc(void *param)
{
struct aciodrv_device_ctx *device = (struct aciodrv_device_ctx *) param;
struct ac_io_panb_poll_in poll_in;
bool stop;
do {
aciodrv_panb_recv_poll(device, &poll_in);
EnterCriticalSection(&keypair_lock);
memcpy(_keypair, poll_in.keypair, AC_IO_PANB_MAX_KEYPAIRS);
LeaveCriticalSection(&keypair_lock);
EnterCriticalSection(&auto_poll_stop_lock);
stop = auto_poll_stop;
stop = auto_poll_stop;
LeaveCriticalSection(&auto_poll_stop_lock);
} while (!stop);
return 0;
}
bool aciodrv_proc_panb_init(struct aciodrv_device_ctx *device)
{
log_assert(device);
if (!aciodrv_panb_start_auto_input(device, 0, AC_IO_PANB_NUM_NODES)) {
return false;
}
auto_poll_stop = false;
InitializeCriticalSection(&keypair_lock);
InitializeCriticalSection(&auto_poll_stop_lock);
auto_poll_threadid = thread_create(auto_poll_proc, (void *)device, 0x4000, 0);
auto_poll_threadid =
thread_create(auto_poll_proc, (void *) device, 0x4000, 0);
return true;
}
bool aciodrv_proc_panb_get_state(uint8_t *button_state)
{
struct ac_io_panb_keypair keypair[AC_IO_PANB_MAX_KEYPAIRS];
EnterCriticalSection(&keypair_lock);
memcpy(keypair, _keypair, AC_IO_PANB_MAX_KEYPAIRS);
memcpy(keypair, _keypair, AC_IO_PANB_MAX_KEYPAIRS);
LeaveCriticalSection(&keypair_lock);
/* splice the keypairs into separate button values */
for (int i=0; i<AC_IO_PANB_MAX_KEYPAIRS; i++) {
uint8_t but1 = keypair[i].key1;
uint8_t but2 = keypair[i].key2;
button_state[2*i] = but1;
button_state[2*i+1] = but2;
for (int i = 0; i < AC_IO_PANB_MAX_KEYPAIRS; i++) {
uint8_t but1 = keypair[i].key1;
uint8_t but2 = keypair[i].key2;
button_state[2 * i] = but1;
button_state[2 * i + 1] = but2;
}
return true;
}
@@ -78,13 +79,13 @@ void aciodrv_proc_panb_fini(struct aciodrv_device_ctx *device)
EnterCriticalSection(&auto_poll_stop_lock);
auto_poll_stop = true;
LeaveCriticalSection(&auto_poll_stop_lock);
thread_join(auto_poll_threadid, NULL);
thread_destroy(auto_poll_threadid);
DeleteCriticalSection(&keypair_lock);
DeleteCriticalSection(&auto_poll_stop_lock);
/* reset is the only way to disable the auto polling on device side */
aciodrv_device_reset(device);
}

View File

@@ -4,14 +4,15 @@
#include "aciodrv/panb.h"
/**
* Initialize a PANB device. This will take care of setting up the auto-poll and processing
* the poll messages in a separate thread (this is necessary as failing to process messages
* fast enough will cause the device to malfunction).
* Initialize a PANB device. This will take care of setting up the auto-poll and
* processing the poll messages in a separate thread (this is necessary as
* failing to process messages fast enough will cause the device to
* malfunction).
*
* @param device Context of opened device
* @return True if successful, false on error.
* @note This function spawns a thread. Caller must call aciodrv_proc_panb_fini to properly
* terminate.
* @note This function spawns a thread. Caller must call aciodrv_proc_panb_fini
* to properly terminate.
*/
bool aciodrv_proc_panb_init(struct aciodrv_device_ctx *device);
@@ -19,13 +20,15 @@ bool aciodrv_proc_panb_init(struct aciodrv_device_ctx *device);
* Retrieve latest known button state from the PANB device.
*
* @param button_state 28 cell array to store button state
* (mandatory, upon calling the array contains values between 0 to 15 indicating the keys velocity).
* (mandatory, upon calling the array contains values between 0 to 15
* indicating the keys velocity).
* @return True on success, false on error.
*/
bool aciodrv_proc_panb_get_state(uint8_t *button_state);
/**
* Properly terminate the thread and reset the device (this is the only way to stop the auto polling).
* Properly terminate the thread and reset the device (this is the only way to
* stop the auto polling).
*/
void aciodrv_proc_panb_fini(struct aciodrv_device_ctx *device);

View File

@@ -12,7 +12,7 @@
#include "util/mem.h"
/* Enable to dump all data to the logger */
//#define AC_IO_MSG_LOG
// #define AC_IO_MSG_LOG
#define ACIO_MAX_NODES_PER_PORT 16
@@ -87,8 +87,11 @@ static bool aciodrv_device_init(struct aciodrv_device_ctx *device)
}
#ifdef AC_IO_MSG_LOG
static void
aciodrv_device_log_buffer(struct aciodrv_device_ctx *device, const char *msg, const uint8_t *buffer, int length)
static void aciodrv_device_log_buffer(
struct aciodrv_device_ctx *device,
const char *msg,
const uint8_t *buffer,
int length)
{
char str[4096];
@@ -97,7 +100,8 @@ aciodrv_device_log_buffer(struct aciodrv_device_ctx *device, const char *msg, co
}
#endif
static bool aciodrv_device_send(struct aciodrv_device_ctx *device, const uint8_t *buffer, int length)
static bool aciodrv_device_send(
struct aciodrv_device_ctx *device, const uint8_t *buffer, int length)
{
uint8_t send_buf[512];
int send_buf_pos = 0;
@@ -138,15 +142,20 @@ static bool aciodrv_device_send(struct aciodrv_device_ctx *device, const uint8_t
aciodrv_device_log_buffer(device, "Send (2)", send_buf, send_buf_pos);
#endif
if (aciodrv_port_write(device->fd, send_buf, send_buf_pos) != send_buf_pos) {
log_warning("[%p] Sending data with length %d failed", device->fd, send_buf_pos);
if (aciodrv_port_write(device->fd, send_buf, send_buf_pos) !=
send_buf_pos) {
log_warning(
"[%p] Sending data with length %d failed",
device->fd,
send_buf_pos);
return false;
}
return true;
}
static int aciodrv_device_receive(struct aciodrv_device_ctx *device, uint8_t *buffer, int max_resp_size)
static int aciodrv_device_receive(
struct aciodrv_device_ctx *device, uint8_t *buffer, int max_resp_size)
{
uint8_t recv_buf[512];
int recv_size = 0;
@@ -161,7 +170,6 @@ static int aciodrv_device_receive(struct aciodrv_device_ctx *device, uint8_t *bu
read = aciodrv_port_read(device->fd, recv_buf, 1);
} while (recv_buf[0] == AC_IO_SOF);
if (read > 0) {
/* recv_buf[0] is already the first byte of the message.
now read until nothing's left */
@@ -189,8 +197,8 @@ static int aciodrv_device_receive(struct aciodrv_device_ctx *device, uint8_t *bu
/* next byte is our real data
overwrite escape byte */
do {
read = aciodrv_port_read(
device->fd, recv_buf + recv_size, 1);
read =
aciodrv_port_read(device->fd, recv_buf + recv_size, 1);
} while (read == 0);
if (read < 0) {
@@ -204,7 +212,8 @@ static int aciodrv_device_receive(struct aciodrv_device_ctx *device, uint8_t *bu
if (recv_size > offsetof(struct ac_io_message, cmd.nbytes)) {
// header + data + checksum
expected_size = offsetof(struct ac_io_message, cmd.raw) + ((struct ac_io_message*)recv_buf)->cmd.nbytes + 1;
expected_size = offsetof(struct ac_io_message, cmd.raw) +
((struct ac_io_message *) recv_buf)->cmd.nbytes + 1;
}
}
@@ -215,7 +224,11 @@ static int aciodrv_device_receive(struct aciodrv_device_ctx *device, uint8_t *bu
/* recv_size - 1: omit checksum for checksum calc */
if ((recv_size - 1) > max_resp_size) {
log_warning("[%p] Expected %d got %d", device->fd, max_resp_size - 6, recv_buf[4]);
log_warning(
"[%p] Expected %d got %d",
device->fd,
max_resp_size - 6,
recv_buf[4]);
return -1;
}
for (int i = 0; i < recv_size - 1; i++) {
@@ -254,9 +267,7 @@ static uint8_t aciodrv_device_enum_nodes(struct aciodrv_device_ctx *device)
msg.cmd.count = 0;
if (!aciodrv_send_and_recv(
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + 1)) {
device, &msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Enumerating nodes failed");
return 0;
}
@@ -266,7 +277,10 @@ static uint8_t aciodrv_device_enum_nodes(struct aciodrv_device_ctx *device)
return msg.cmd.count;
}
static bool aciodrv_device_get_version(struct aciodrv_device_ctx *device, uint8_t node_id, struct aciodrv_device_node_version *version)
static bool aciodrv_device_get_version(
struct aciodrv_device_ctx *device,
uint8_t node_id,
struct aciodrv_device_node_version *version)
{
struct ac_io_message msg;
@@ -299,7 +313,10 @@ static bool aciodrv_device_get_version(struct aciodrv_device_ctx *device, uint8_
msg.cmd.version.date,
msg.cmd.version.time);
memcpy(version->product, msg.cmd.version.product_code, ACIO_NODE_PRODUCT_CODE_LEN);
memcpy(
version->product,
msg.cmd.version.product_code,
ACIO_NODE_PRODUCT_CODE_LEN);
version->type = ac_io_u32(msg.cmd.version.type);
version->major = msg.cmd.version.major;
version->minor = msg.cmd.version.minor;
@@ -308,7 +325,8 @@ static bool aciodrv_device_get_version(struct aciodrv_device_ctx *device, uint8_
return true;
}
static bool aciodrv_device_start_node(struct aciodrv_device_ctx *device, uint8_t node_id)
static bool
aciodrv_device_start_node(struct aciodrv_device_ctx *device, uint8_t node_id)
{
struct ac_io_message msg;
@@ -317,9 +335,7 @@ static bool aciodrv_device_start_node(struct aciodrv_device_ctx *device, uint8_t
msg.cmd.nbytes = 0;
if (!aciodrv_send_and_recv(
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + 1)) {
device, &msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Starting node %d failed", node_id);
return false;
}
@@ -334,7 +350,8 @@ struct aciodrv_device_ctx *aciodrv_device_open(const char *port_path, int baud)
return aciodrv_device_open_path(port_path, baud);
}
struct aciodrv_device_ctx *aciodrv_device_open_path(const char *port_path, int baud)
struct aciodrv_device_ctx *
aciodrv_device_open_path(const char *port_path, int baud)
{
HANDLE port = aciodrv_port_open(port_path, baud);
@@ -342,7 +359,8 @@ struct aciodrv_device_ctx *aciodrv_device_open_path(const char *port_path, int b
return NULL;
}
struct aciodrv_device_ctx *device = xmalloc(sizeof(struct aciodrv_device_ctx));
struct aciodrv_device_ctx *device =
xmalloc(sizeof(struct aciodrv_device_ctx));
memset(device, 0, sizeof(struct aciodrv_device_ctx));
device->fd = port;
@@ -384,16 +402,23 @@ uint8_t aciodrv_device_get_node_count(struct aciodrv_device_ctx *device)
return device->node_count;
}
bool aciodrv_device_get_node_product_ident(struct aciodrv_device_ctx *device, uint8_t node_id, char product[ACIO_NODE_PRODUCT_CODE_LEN])
bool aciodrv_device_get_node_product_ident(
struct aciodrv_device_ctx *device,
uint8_t node_id,
char product[ACIO_NODE_PRODUCT_CODE_LEN])
{
if (device->node_count == 0 || node_id > device->node_count) {
return false;
}
memcpy(product, device->node_versions[node_id].product, ACIO_NODE_PRODUCT_CODE_LEN);
memcpy(
product,
device->node_versions[node_id].product,
ACIO_NODE_PRODUCT_CODE_LEN);
return true;
}
uint32_t aciodrv_device_get_node_product_type(struct aciodrv_device_ctx *device, uint8_t node_id)
uint32_t aciodrv_device_get_node_product_type(
struct aciodrv_device_ctx *device, uint8_t node_id)
{
if (device->node_count == 0 || node_id > device->node_count) {
return 0;
@@ -402,7 +427,9 @@ uint32_t aciodrv_device_get_node_product_type(struct aciodrv_device_ctx *device,
return device->node_versions[node_id].type;
}
const struct aciodrv_device_node_version *aciodrv_device_get_node_product_version(struct aciodrv_device_ctx *device, uint8_t node_id)
const struct aciodrv_device_node_version *
aciodrv_device_get_node_product_version(
struct aciodrv_device_ctx *device, uint8_t node_id)
{
if (device->node_count == 0 || node_id > device->node_count) {
return NULL;
@@ -430,7 +457,10 @@ bool aciodrv_send(struct aciodrv_device_ctx *device, struct ac_io_message *msg)
return true;
}
bool aciodrv_recv(struct aciodrv_device_ctx *device, struct ac_io_message *msg, int max_resp_size)
bool aciodrv_recv(
struct aciodrv_device_ctx *device,
struct ac_io_message *msg,
int max_resp_size)
{
#ifdef AC_IO_MSG_LOG
log_info("[%p] Beginning recv: (%d b)", device->fd, max_resp_size);
@@ -441,7 +471,10 @@ bool aciodrv_recv(struct aciodrv_device_ctx *device, struct ac_io_message *msg,
return true;
}
bool aciodrv_send_and_recv(struct aciodrv_device_ctx *device, struct ac_io_message *msg, int max_resp_size)
bool aciodrv_send_and_recv(
struct aciodrv_device_ctx *device,
struct ac_io_message *msg,
int max_resp_size)
{
if (!aciodrv_send(device, msg)) {
return false;

View File

@@ -28,11 +28,13 @@ struct aciodrv_device_node_version {
*/
struct aciodrv_device_ctx *aciodrv_device_open(const char *port_path, int baud)
#ifdef __GNUC__
__attribute__((deprecated("Use aciomgr instead if device is shareable, else aciodrv_device_open_path")))
__attribute__((deprecated("Use aciomgr instead if device is shareable, "
"else aciodrv_device_open_path")))
#endif
;
;
struct aciodrv_device_ctx *aciodrv_device_open_path(const char *port_path, int baud);
struct aciodrv_device_ctx *
aciodrv_device_open_path(const char *port_path, int baud);
/**
* Get the node count on the opened device.
@@ -51,7 +53,10 @@ uint8_t aciodrv_device_get_node_count(struct aciodrv_device_ctx *device);
* @return True on success, false on error. If True the variable product
* contains the identifier of the queried node.
*/
bool aciodrv_device_get_node_product_ident(struct aciodrv_device_ctx *device, uint8_t node_id, char product[ACIO_NODE_PRODUCT_CODE_LEN]);
bool aciodrv_device_get_node_product_ident(
struct aciodrv_device_ctx *device,
uint8_t node_id,
char product[ACIO_NODE_PRODUCT_CODE_LEN]);
/**
* Get the product identifier of an enumerated node.
@@ -60,7 +65,8 @@ bool aciodrv_device_get_node_product_ident(struct aciodrv_device_ctx *device, ui
* @param node_id Id of the node. Needs to be in range of the total node count.
* @return product type ID on success, or 0 on failure
*/
uint32_t aciodrv_device_get_node_product_type(struct aciodrv_device_ctx *device, uint8_t node_id);
uint32_t aciodrv_device_get_node_product_type(
struct aciodrv_device_ctx *device, uint8_t node_id);
/**
* Get the product version of an enumerated node.
@@ -69,7 +75,9 @@ uint32_t aciodrv_device_get_node_product_type(struct aciodrv_device_ctx *device,
* @param node_id Id of the node. Needs to be in range of the total node count.
* @return Pointer to the version struct
*/
const struct aciodrv_device_node_version *aciodrv_device_get_node_product_version(struct aciodrv_device_ctx *device, uint8_t node_id);
const struct aciodrv_device_node_version *
aciodrv_device_get_node_product_version(
struct aciodrv_device_ctx *device, uint8_t node_id);
/**
* Send a message to the ACIO bus and receive an answer.
@@ -82,7 +90,10 @@ const struct aciodrv_device_node_version *aciodrv_device_get_node_product_versio
* @param resp_size Size of the expecting response.
* @return True on success, false on error.
*/
bool aciodrv_send_and_recv(struct aciodrv_device_ctx *device, struct ac_io_message *msg, int max_resp_size);
bool aciodrv_send_and_recv(
struct aciodrv_device_ctx *device,
struct ac_io_message *msg,
int max_resp_size);
/**
* Send a message to the ACIO bus.
@@ -90,7 +101,8 @@ bool aciodrv_send_and_recv(struct aciodrv_device_ctx *device, struct ac_io_messa
* @param device Context of opened device
* @param msg Msg to send to the bus.
* @return True on success, false on error.
* @note Prefer the use of aciodrv_send_and_recv when possible. This is for commands which don't trigger a reply.
* @note Prefer the use of aciodrv_send_and_recv when possible. This is for
* commands which don't trigger a reply.
*/
bool aciodrv_send(struct aciodrv_device_ctx *device, struct ac_io_message *msg);
@@ -101,9 +113,13 @@ bool aciodrv_send(struct aciodrv_device_ctx *device, struct ac_io_message *msg);
* @param msg Msg to send to the bus. Make sure that the buffer
* is big enough to receive the response.
* @return True on success, false on error.
* @note Prefer the use of aciodrv_send_and_recv when possible. This is for unsollicited incoming messages.
* @note Prefer the use of aciodrv_send_and_recv when possible. This is for
* unsollicited incoming messages.
*/
bool aciodrv_recv(struct aciodrv_device_ctx *device, struct ac_io_message *msg, int max_resp_size);
bool aciodrv_recv(
struct aciodrv_device_ctx *device,
struct ac_io_message *msg,
int max_resp_size);
/**
* Reset an opened device.
@@ -115,7 +131,7 @@ bool aciodrv_device_reset(struct aciodrv_device_ctx *device);
/**
* Close the previously opened ACIO device.
*
*
* @param device Context of opened device
*/
void aciodrv_device_close(struct aciodrv_device_ctx *device);

View File

@@ -9,9 +9,7 @@
#include "util/log.h"
bool aciodrv_h44b_init(
struct aciodrv_device_ctx *device,
uint8_t node_id)
bool aciodrv_h44b_init(struct aciodrv_device_ctx *device, uint8_t node_id)
{
// unlike input devices like KFCA, H44B has no watchdog or special init code
// requirements - shared ACIO node initialisation is enough
@@ -34,9 +32,7 @@ bool aciodrv_h44b_lights(
msg.cmd.h44b_output = *lights;
if (!aciodrv_send_and_recv(
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + 1)) {
device, &msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Polling of node %d failed", node_id + 1);
return false;
}

View File

@@ -1,8 +1,8 @@
#ifndef ACIODRV_H44B_H
#define ACIODRV_H44B_H
#include "aciodrv/device.h"
#include "acio/h44b.h"
#include "aciodrv/device.h"
/**
* Initialize an H44B node.

View File

@@ -8,8 +8,7 @@
#include "util/log.h"
static bool aciodrv_icca_queue_loop_start(
struct aciodrv_device_ctx *device,
uint8_t node_id)
struct aciodrv_device_ctx *device, uint8_t node_id)
{
struct ac_io_message msg;
@@ -21,9 +20,7 @@ static bool aciodrv_icca_queue_loop_start(
msg.cmd.status = 0;
if (!aciodrv_send_and_recv(
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + 1)) {
device, &msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Starting queue loop failed");
return false;
}
@@ -137,16 +134,14 @@ bool aciodrv_icca_read_card(
return true;
}
bool aciodrv_icca_is_slotted(
struct aciodrv_device_ctx *device,
uint8_t node_id)
bool aciodrv_icca_is_slotted(struct aciodrv_device_ctx *device, uint8_t node_id)
{
const struct aciodrv_device_node_version *version;
version = aciodrv_device_get_node_product_version(device, node_id);
// current heuristic is to check if version >= 1.5
if (version) {
if (version->major == 1) {
if (version->major == 1) {
if (version->minor >= 5) {
return false;
}
@@ -157,8 +152,7 @@ bool aciodrv_icca_is_slotted(
}
bool aciodrv_icca_poll_felica(
struct aciodrv_device_ctx *device,
uint8_t node_id)
struct aciodrv_device_ctx *device, uint8_t node_id)
{
struct ac_io_message msg;

View File

@@ -74,9 +74,9 @@ bool aciodrv_icca_read_card(
/**
* Uses some heruistics based on the product ident to determine if the detected
* device is a slotted (true) or wavepass reader (false).
*
*
* This function will also return false if the provided node_id is invalid.
*
*
* @param device Context of opened device
* @param node_id Id of the node to query (0 based).
* @return True on slotted, false on wavepass.
@@ -85,18 +85,17 @@ bool aciodrv_icca_read_card(
* @see driver.h
*/
bool aciodrv_icca_is_slotted(
struct aciodrv_device_ctx *device,
uint8_t node_id);
struct aciodrv_device_ctx *device, uint8_t node_id);
/**
* Polls the felica chip on wavepass readers. This will cause the state of the
* reader to be AC_IO_ICCA_STATUS_BUSY_NEW for a few polls, before returning
* either: AC_IO_ICCA_STATUS_IDLE_NEW or AC_IO_ICCA_STATUS_GOT_UID.
*
*
* The user should take care to call this every so often to actually get new
* felica UIDs, instead of just old NFC idents. The game seems to do it every
* 5 or so polls after the last AC_IO_ICCA_STATUS_BUSY_NEW poll.
*
*
* @param device Context of opened device
* @param node_id Id of the node to query (0 based).
* @return True on success, false on error.
@@ -105,7 +104,6 @@ bool aciodrv_icca_is_slotted(
* @see driver.h
*/
bool aciodrv_icca_poll_felica(
struct aciodrv_device_ctx *device,
uint8_t node_id);
struct aciodrv_device_ctx *device, uint8_t node_id);
#endif

View File

@@ -7,9 +7,8 @@
#include "util/log.h"
static bool aciodrv_kfca_watchdog_start(
struct aciodrv_device_ctx *device,
uint8_t node_id)
static bool
aciodrv_kfca_watchdog_start(struct aciodrv_device_ctx *device, uint8_t node_id)
{
struct ac_io_message msg;
@@ -25,11 +24,15 @@ static bool aciodrv_kfca_watchdog_start(
if (!aciodrv_send_and_recv(
device, &msg, offsetof(struct ac_io_message, cmd.raw) + 2)) {
log_warning("Starting watchdog failed"); return false;
log_warning("Starting watchdog failed");
return false;
}
log_warning("Started watchdog of node %d, sz: %d, status: %d",
node_id, msg.cmd.nbytes, msg.cmd.status);
log_warning(
"Started watchdog of node %d, sz: %d, status: %d",
node_id,
msg.cmd.nbytes,
msg.cmd.status);
return true;
}
@@ -56,9 +59,7 @@ bool aciodrv_kfca_amp(
msg.cmd.raw[3] = subwoofer;
if (!aciodrv_send_and_recv(
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + 1)) {
device, &msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Setting AMP failed");
return false;
}
@@ -68,9 +69,7 @@ bool aciodrv_kfca_amp(
return true;
}
bool aciodrv_kfca_init(
struct aciodrv_device_ctx *device,
uint8_t node_id)
bool aciodrv_kfca_init(struct aciodrv_device_ctx *device, uint8_t node_id)
{
log_assert(device);

View File

@@ -2,6 +2,7 @@
#define ACIODRV_KFCA_H
#include "acio/kfca.h"
#include "aciodrv/device.h"
/**
* Initialize an KFCA node.

View File

@@ -5,10 +5,11 @@
#include "aciodrv/device.h"
#include "aciodrv/panb.h"
#include "util/thread.h"
#include "util/log.h"
#include "util/thread.h"
bool aciodrv_panb_start_auto_input(struct aciodrv_device_ctx *device, uint8_t node_id, uint8_t node_count)
bool aciodrv_panb_start_auto_input(
struct aciodrv_device_ctx *device, uint8_t node_id, uint8_t node_count)
{
log_assert(device);
struct ac_io_message msg;
@@ -33,34 +34,40 @@ bool aciodrv_panb_start_auto_input(struct aciodrv_device_ctx *device, uint8_t no
return true;
}
bool aciodrv_panb_recv_poll(struct aciodrv_device_ctx *device, struct ac_io_panb_poll_in *poll_in)
bool aciodrv_panb_recv_poll(
struct aciodrv_device_ctx *device, struct ac_io_panb_poll_in *poll_in)
{
log_assert(device);
struct ac_io_message msg;
struct ac_io_panb_poll_in *poll_res = (struct ac_io_panb_poll_in *) &msg.cmd.raw;
struct ac_io_panb_poll_in *poll_res =
(struct ac_io_panb_poll_in *) &msg.cmd.raw;
msg.cmd.code = ac_io_u16(AC_IO_CMD_PANB_POLL_REPLY);
msg.cmd.nbytes = sizeof(struct ac_io_panb_poll_in);
if (!aciodrv_recv(device,
&msg, offsetof(struct ac_io_message, cmd.raw) + msg.cmd.nbytes + 1)) {
if (!aciodrv_recv(
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + msg.cmd.nbytes + 1)) {
log_warning("Getting state failed");
return false;
}
if (poll_in != NULL){
if (poll_in != NULL) {
memcpy(poll_in, poll_res, sizeof(struct ac_io_panb_poll_in));
}
return true;
}
bool aciodrv_panb_send_lamp(struct aciodrv_device_ctx *device,
uint8_t node_id, struct ac_io_panb_poll_out *state)
bool aciodrv_panb_send_lamp(
struct aciodrv_device_ctx *device,
uint8_t node_id,
struct ac_io_panb_poll_out *state)
{
log_assert(device);
struct ac_io_message msg;
/* only the first node is handling the commands */
if (node_id != 0) {
return true;

View File

@@ -11,39 +11,43 @@
* @param node_count The number of nodes to poll.
* @return True if successful, false on error.
* @note node_id should be 0, PANB internally manages the other nodes.
* @note Upon calling, the device will stop replying to commands and just keep sending
* AC_IO_CMD_PANB_POLL_REPLY messages indefinitely. Failure to retrieve them fast enough
* will cause the device to malfunction. It is thus advised to make use of the aciodrv-proc
* module to spawn a thread that will handle these messages and provide an easy access to the
* latest input state.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool aciodrv_panb_start_auto_input(struct aciodrv_device_ctx *device, uint8_t node_id, uint8_t node_count);
/**
* Retrieve a AC_IO_CMD_PANB_POLL_REPLY message from a PANB device. This assumes that there
* is such message incoming (ie. that start_auto_input has been called prior).
*
* @param device Context of opened device.
* @param poll_in Buffer to hold the received message, or NULL.
* @return True if successful, false on error.
* @note node_id should be 0, PANB internally manages the other nodes.
* @note Failure to retrieve the incoming messages fast enough will cause the device to malfunction.
* It is thus advised to make use of the aciodrv-proc module to spawn a thread that will handle these
* @note Upon calling, the device will stop replying to commands and just keep
* sending AC_IO_CMD_PANB_POLL_REPLY messages indefinitely. Failure to retrieve
* them fast enough will cause the device to malfunction. It is thus advised to
* make use of the aciodrv-proc module to spawn a thread that will handle these
* messages and provide an easy access to the latest input state.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool aciodrv_panb_recv_poll(struct aciodrv_device_ctx *device, struct ac_io_panb_poll_in *poll_in);
bool aciodrv_panb_start_auto_input(
struct aciodrv_device_ctx *device, uint8_t node_id, uint8_t node_count);
/**
* Retrieve a AC_IO_CMD_PANB_POLL_REPLY message from a PANB device. This assumes
* that there is such message incoming (ie. that start_auto_input has been
* called prior).
*
* @param device Context of opened device.
* @param poll_in Buffer to hold the received message, or NULL.
* @return True if successful, false on error.
* @note node_id should be 0, PANB internally manages the other nodes.
* @note Failure to retrieve the incoming messages fast enough will cause the
* device to malfunction. It is thus advised to make use of the aciodrv-proc
* module to spawn a thread that will handle these messages and provide an easy
* access to the latest input state.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool aciodrv_panb_recv_poll(
struct aciodrv_device_ctx *device, struct ac_io_panb_poll_in *poll_in);
/**
* Light lamps on a PANB device.
*
* @param node_id Id of the node to query (0 based).
* @param state Pointer to a lamp state struct
* @param state Pointer to a lamp state struct
* (mandatory).
* @return True on success, false on error.
* @note node_id should be 0, PANB internally manages the other nodes.
@@ -51,6 +55,9 @@ bool aciodrv_panb_recv_poll(struct aciodrv_device_ctx *device, struct ac_io_panb
* device driver foundation.
* @see driver.h
*/
bool aciodrv_panb_send_lamp(struct aciodrv_device_ctx *device, uint8_t node_id, struct ac_io_panb_poll_out *state);
bool aciodrv_panb_send_lamp(
struct aciodrv_device_ctx *device,
uint8_t node_id,
struct ac_io_panb_poll_out *state);
#endif

View File

@@ -148,7 +148,8 @@ int aciodrv_port_write(HANDLE port_fd, const void *bytes, int nbytes)
}
if (!WriteFile(port_fd, bytes, nbytes, &nwrit, NULL)) {
log_warning("[%p] WriteFile failed: err = %lu", port_fd, GetLastError());
log_warning(
"[%p] WriteFile failed: err = %lu", port_fd, GetLastError());
return -1;
}

View File

@@ -40,7 +40,7 @@ int aciodrv_port_write(HANDLE port_fd, const void *bytes, int nbytes);
/**
* Close the previously opened com port.
*
*
* @param port_fd HANDLE of opened serial port
*/
void aciodrv_port_close(HANDLE port_fd);

View File

@@ -8,9 +8,7 @@
#include "util/log.h"
static bool aciodrv_rvol_change_expand_mode(
struct aciodrv_device_ctx *device,
uint8_t node_id,
uint8_t mode)
struct aciodrv_device_ctx *device, uint8_t node_id, uint8_t mode)
{
struct ac_io_message msg;
@@ -28,15 +26,12 @@ static bool aciodrv_rvol_change_expand_mode(
return false;
}
log_info("I/O expand mode set %d, mode: %d",
node_id, mode);
log_info("I/O expand mode set %d, mode: %d", node_id, mode);
return true;
}
bool aciodrv_rvol_init(
struct aciodrv_device_ctx *device,
uint8_t node_id)
bool aciodrv_rvol_init(struct aciodrv_device_ctx *device, uint8_t node_id)
{
log_assert(device);

View File

@@ -147,7 +147,7 @@ void ac_io_emu_icca_dispatch_request(
break;
case AC_IO_ICCA_CMD_SET_SLOT_STATE: {
if(icca->version == v150) {
if (icca->version == v150) {
ac_io_emu_icca_send_state(icca, req, 0, false);
} else {
struct ac_io_icca_misc *misc =
@@ -267,8 +267,7 @@ static void ac_io_emu_icca_cmd_send_version(
} else {
// probably log invalid version here
log_warning(
"Unknown ICCA version: %d emulation requested",
icca->version);
"Unknown ICCA version: %d emulation requested", icca->version);
}
resp.cmd.version.revision = 0x00;
@@ -487,7 +486,7 @@ ac_io_emu_icca_cipher(struct ac_io_emu_icca *icca, uint8_t *data, size_t length)
// process data
data[i] =
(uint8_t)(icca->cipher_keys[0] >> (((3 - count4) << 3)) ^ data[i]);
(uint8_t) (icca->cipher_keys[0] >> (((3 - count4) << 3)) ^ data[i]);
}
}
@@ -512,7 +511,7 @@ static void ac_io_emu_icca_cipher_set_key(
resp.cmd.raw[0] = (reader_key >> 24) & 0xFF;
resp.cmd.raw[1] = (reader_key >> 16) & 0xFF;
resp.cmd.raw[2] = (reader_key >> 8) & 0xFF;
resp.cmd.raw[3] = (reader_key) & 0xFF;
resp.cmd.raw[3] = (reader_key) &0xFF;
// so I looked these constants up, this isn't actually a secure key
// generator it's actually Marsaglia's "KISS" algorithm with different

View File

@@ -105,7 +105,6 @@ struct aciomgr_port_dispatcher *aciomgr_port_init(const char *path, int baud)
return NULL;
}
struct aciomgr_port_dispatcher *entry;
EnterCriticalSection(&mgr_cs);

View File

@@ -29,7 +29,6 @@ bool aciotest_bi2a_sdvx_handler_update(
return false;
}
pin.raw[0] = ac_io_u16(pin.raw[0]);
pin.raw[1] = ac_io_u16(pin.raw[1]);

View File

@@ -5,7 +5,6 @@
#include "aciodrv/icca.h"
#define IDLE_RESPONSES_BETWEEN_FELICA_POLLS 5
struct icca_handler_ctx {
@@ -19,7 +18,7 @@ bool aciotest_icca_handler_init(
{
*ctx = malloc(sizeof(struct icca_handler_ctx));
struct icca_handler_ctx *icca_ctx = (struct icca_handler_ctx*)*ctx;
struct icca_handler_ctx *icca_ctx = (struct icca_handler_ctx *) *ctx;
icca_ctx->init = false;
icca_ctx->slotted_reader = true;
@@ -34,7 +33,7 @@ bool aciotest_icca_handler_init(
bool aciotest_icca_handler_update(
struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx)
{
struct icca_handler_ctx *icca_ctx = (struct icca_handler_ctx*)ctx;
struct icca_handler_ctx *icca_ctx = (struct icca_handler_ctx *) ctx;
if (icca_ctx->init == false) {
icca_ctx->init = true;

View File

@@ -85,8 +85,8 @@ int main(int argc, char **argv)
log_to_writer(log_writer_stdout, NULL);
struct aciodrv_device_ctx *device = aciodrv_device_open_path(argv[1], atoi(argv[2]));
struct aciodrv_device_ctx *device =
aciodrv_device_open_path(argv[1], atoi(argv[2]));
if (!device) {
printf("Opening acio device failed\n");

View File

@@ -3,27 +3,29 @@
#include <stdio.h>
#include <stdlib.h>
#include "aciodrv/panb.h"
#include "aciodrv-proc/panb.h"
#include "aciodrv/panb.h"
struct panb_handler_ctx {
bool running;
};
bool aciotest_panb_handler_init(struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx)
bool aciotest_panb_handler_init(
struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx)
{
if (node_id != 0) {
return true;
}
*ctx = malloc(sizeof(struct panb_handler_ctx));
struct panb_handler_ctx *panb_ctx = (struct panb_handler_ctx*)*ctx;
struct panb_handler_ctx *panb_ctx = (struct panb_handler_ctx *) *ctx;
panb_ctx->running = true;
return aciodrv_proc_panb_init(device);
}
bool aciotest_panb_handler_update(struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx)
bool aciotest_panb_handler_update(
struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx)
{
uint8_t button[AC_IO_PANB_MAX_KEYS];
struct ac_io_panb_poll_out state;
@@ -32,19 +34,19 @@ bool aciotest_panb_handler_update(struct aciodrv_device_ctx *device, uint8_t nod
if (node_id != 0) {
return true;
}
if (!panb_ctx->running) {
printf(">>> PANB:\nDevice has been closed. Press Ctrl+C to exit.");
return true;
}
if (!aciodrv_proc_panb_get_state(button)) {
return false;
}
printf(">>> PANB:\nPress first and last keys to close device\n");
for (int i=0; i<AC_IO_PANB_MAX_KEYS; i++) {
for (int i = 0; i < AC_IO_PANB_MAX_KEYS; i++) {
printf("%01X ", button[i]);
}
printf("\n");
@@ -52,25 +54,25 @@ bool aciotest_panb_handler_update(struct aciodrv_device_ctx *device, uint8_t nod
/* I added a key combo to properly close the module.
* Leaving the PANB device in autopolling state without ever
* reading packets from the serial interface eventually
* makes it fall into a state where it doesn't send anything anymore
* makes it fall into a state where it doesn't send anything anymore
* and won't even respond to a reset, thus requiring a power cycle.
*/
if (button[0] && button[AC_IO_PANB_MAX_KEYS-1]) {
if (button[0] && button[AC_IO_PANB_MAX_KEYS - 1]) {
aciodrv_proc_panb_fini(device);
panb_ctx->running = false;
return true;
}
/* light the panel */
for (int i=0; i<AC_IO_PANB_MAX_KEYS; i++) {
state.key[i].green = (button[i])? 0x7F : 0;
for (int i = 0; i < AC_IO_PANB_MAX_KEYS; i++) {
state.key[i].green = (button[i]) ? 0x7F : 0;
state.key[i].red = 0;
state.key[i].blue = (button[i])? 0x23 : 0;
state.key[i].blue = (button[i]) ? 0x23 : 0;
}
if (!aciodrv_panb_send_lamp(device, node_id, &state)) {
return false;
}
return true;
}

View File

@@ -6,7 +6,9 @@
#include "aciodrv/device.h"
bool aciotest_panb_handler_init(struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx);
bool aciotest_panb_handler_update(struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx);
bool aciotest_panb_handler_init(
struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx);
bool aciotest_panb_handler_update(
struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx);
#endif

View File

@@ -54,8 +54,7 @@ bool aciotest_rvol_handler_update(
selected_light,
pin.spinners[2] / 2,
pin.spinners[3] / 2,
pin.spinners[4] / 2
);
pin.spinners[4] / 2);
memset(&pout, 0, sizeof(pout));

View File

@@ -51,17 +51,17 @@ LSTATUS my_RegCloseKey(HKEY hKey);
LSTATUS (*real_RegOpenKeyA)(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult);
LSTATUS (*real_RegEnumKeyA)
LSTATUS(*real_RegEnumKeyA)
(HKEY hKey, DWORD dwIndex, LPSTR lpName, DWORD cchName);
LSTATUS (*real_RegOpenKeyExA)
LSTATUS(*real_RegOpenKeyExA)
(HKEY hKey,
LPCSTR lpSubKey,
DWORD ulOptions,
REGSAM samDesired,
PHKEY phkResult);
LSTATUS (*real_RegQueryValueExA)
LSTATUS(*real_RegQueryValueExA)
(HKEY hKey,
LPCSTR lpValueName,
LPDWORD lpReserved,

View File

@@ -10,8 +10,7 @@
#define ASIOHOOK_CONFIG_IO_DEFAULT_FORCE_ASIO_VALUE false
#define ASIOHOOK_CONFIG_IO_DEFAULT_FORCE_WASAPI_VALUE false
#define ASIOHOOK_CONFIG_IO_DEFAULT_ASIO_DEVICE_NAME_VALUE \
"XONAR SOUND CARD(64)"
#define ASIOHOOK_CONFIG_IO_DEFAULT_ASIO_DEVICE_NAME_VALUE "XONAR SOUND CARD(64)"
void asiohook_config_init(struct cconfig *config)
{

View File

@@ -105,7 +105,6 @@ bool ddr_io_init(
thread_join_t thread_join,
thread_destroy_t thread_destroy);
/* used to poll the IO for input, note that this is also where lights are
flushed to the device for geninput */
uint32_t ddr_io_read_pad(void);

View File

@@ -70,7 +70,8 @@ enum iidx_io_panel_light {
IIDX_IO_PANEL_LIGHT_EFFECT = 3,
};
/* Bit mapping for the top lamps from left to right when facing cabinet screen */
/* Bit mapping for the top lamps from left to right when facing cabinet screen
*/
enum iidx_io_top_lamp {
IIDX_IO_TOP_LAMP_LEFT_BLUE = 0,

View File

@@ -106,7 +106,8 @@ void jb_io_set_rgb_led(
bool jb_io_write_lights(void);
/* Select operating mode for the panel. Should be immediately sent to the IOPCB */
/* Select operating mode for the panel. Should be immediately sent to the IOPCB
*/
bool jb_io_set_panel_mode(enum jb_io_panel_mode mode);

View File

@@ -103,8 +103,6 @@ uint16_t sdvx_io_get_spinner_pos(uint8_t spinner_no);
Range is between 0-96, where 0 is MAX and 96 is LOW. */
bool sdvx_io_set_amp_volume(
uint8_t primary,
uint8_t headphone,
uint8_t subwoofer);
uint8_t primary, uint8_t headphone, uint8_t subwoofer);
#endif

View File

@@ -14,9 +14,8 @@
// in all inputs and outputs (over sub IO) other than 14 keys to not work.
static const uint8_t _BIO2DR_BI2A_IIDX_INIT_DATA = 0x2D;
static bool bio2drv_bi2a_iidx_init_io(
struct aciodrv_device_ctx *device,
uint8_t node_id)
static bool
bio2drv_bi2a_iidx_init_io(struct aciodrv_device_ctx *device, uint8_t node_id)
{
struct ac_io_message msg;
@@ -28,9 +27,7 @@ static bool bio2drv_bi2a_iidx_init_io(
msg.cmd.param = _BIO2DR_BI2A_IIDX_INIT_DATA;
if (!aciodrv_send_and_recv(
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + 1)) {
device, &msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Init node failed");
return 0;
}
@@ -41,8 +38,7 @@ static bool bio2drv_bi2a_iidx_init_io(
}
static bool bio2drv_bi2a_iidx_watchdog_start(
struct aciodrv_device_ctx *device,
uint8_t node_id)
struct aciodrv_device_ctx *device, uint8_t node_id)
{
log_assert(device);

View File

@@ -15,9 +15,7 @@
* device driver foundation.
* @see driver.h
*/
bool bio2drv_bi2a_iidx_init(
struct aciodrv_device_ctx *device,
uint8_t node_id);
bool bio2drv_bi2a_iidx_init(struct aciodrv_device_ctx *device, uint8_t node_id);
/**
* Poll the BI2A board

View File

@@ -12,7 +12,8 @@
static const uint8_t _BIO2DR_BI2A_SDVX_INIT_DATA = 0x3B;
// this is probably InitIO
static bool bio2drv_bi2a_sdvx_init_io(struct aciodrv_device_ctx *device, uint8_t node_id)
static bool
bio2drv_bi2a_sdvx_init_io(struct aciodrv_device_ctx *device, uint8_t node_id)
{
struct ac_io_message msg;
@@ -24,9 +25,7 @@ static bool bio2drv_bi2a_sdvx_init_io(struct aciodrv_device_ctx *device, uint8_t
msg.cmd.param = _BIO2DR_BI2A_SDVX_INIT_DATA;
if (!aciodrv_send_and_recv(
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + 1)) {
device, &msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Init node failed");
return 0;
}
@@ -36,7 +35,8 @@ static bool bio2drv_bi2a_sdvx_init_io(struct aciodrv_device_ctx *device, uint8_t
return 1;
}
static bool bio2drv_bi2a_sdvx_watchdog_start(struct aciodrv_device_ctx *device, uint8_t node_id)
static bool bio2drv_bi2a_sdvx_watchdog_start(
struct aciodrv_device_ctx *device, uint8_t node_id)
{
log_assert(device);
@@ -95,9 +95,7 @@ bool bio2drv_bi2a_sdvx_amp(
msg.cmd.raw[3] = right;
if (!aciodrv_send_and_recv(
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + 1)) {
device, &msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Setting AMP failed");
return false;
}

View File

@@ -15,9 +15,7 @@
* device driver foundation.
* @see driver.h
*/
bool bio2drv_bi2a_sdvx_init(
struct aciodrv_device_ctx *device,
uint8_t node_id);
bool bio2drv_bi2a_sdvx_init(struct aciodrv_device_ctx *device, uint8_t node_id);
/**
* Poll the board

View File

@@ -50,10 +50,10 @@ static bool check_property(
return false;
}
static bool check_id(
HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA PDeviceInfoData)
static bool check_id(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA PDeviceInfoData)
{
if (CM_Get_Device_IDA(PDeviceInfoData->DevInst, work_buffer, sizeof(work_buffer), 0)) {
if (CM_Get_Device_IDA(
PDeviceInfoData->DevInst, work_buffer, sizeof(work_buffer), 0)) {
return false;
}

View File

@@ -175,7 +175,8 @@ static void bio2_emu_bi2a_send_status(
ac_io_emu_response_push(emu, &resp, 0);
}
static int16_t tt_mult_delta(size_t tt_no) {
static int16_t tt_mult_delta(size_t tt_no)
{
int16_t current_tt = iidx_io_ep2_get_turntable(tt_no);
int16_t delta = get_wrapped_delta_s16(current_tt, tt_last[tt_no], 256);

View File

@@ -382,8 +382,8 @@ static INT_PTR lights_handle_pulse_tick(HWND hwnd)
}
bias = (float) (ui->lights[light_no].value_min);
scale =
(float) (ui->lights[light_no].value_max - ui->lights[light_no].value_min);
scale = (float) (ui->lights[light_no].value_max -
ui->lights[light_no].value_min);
/* Intensity perception is non-linear. Pulse quadratically. */

View File

@@ -117,14 +117,14 @@ int main(int argc, char **argv)
if (!mapper_config_load(schema->name)) {
log_info("Initializing empty config for %s", schema->name);
mapper_set_nlights((uint8_t)(max_light + 1));
mapper_set_nlights((uint8_t) (max_light + 1));
mapper_set_nanalogs((uint8_t) schema->nanalogs);
} else {
// make sure that these are right
if (mapper_get_nlights() != (max_light + 1)) {
log_info("Updating nlights for %s", schema->name);
mapper_set_nlights((uint8_t)(max_light + 1));
mapper_set_nlights((uint8_t) (max_light + 1));
}
if (mapper_get_nanalogs() != schema->nanalogs) {

View File

@@ -24,7 +24,7 @@ void spinner_init(HINSTANCE inst)
wcx.cbSize = sizeof(wcx);
wcx.lpfnWndProc = spinner_wnd_proc;
wcx.hInstance = inst;
wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcx.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
wcx.lpszClassName = spinner_cls;
RegisterClassEx(&wcx);

View File

@@ -18,8 +18,10 @@
#define D3D9EXHOOK_CONFIG_GFX_FORCED_REFRESHRATE_KEY "gfx.forced_refresh_rate"
#define D3D9EXHOOK_CONFIG_GFX_DEVICE_ADAPTER_KEY "gfx.device_adapter"
#define D3D9EXHOOK_CONFIG_GFX_FORCE_ORIENTATION_KEY "gfx.force_orientation"
#define D3D9EXHOOK_CONFIG_GFX_FORCE_SCREEN_RES_WIDTH_KEY "gfx.force_screen_res.width"
#define D3D9EXHOOK_CONFIG_GFX_FORCE_SCREEN_RES_HEIGHT_KEY "gfx.force_screen_res.height"
#define D3D9EXHOOK_CONFIG_GFX_FORCE_SCREEN_RES_WIDTH_KEY \
"gfx.force_screen_res.width"
#define D3D9EXHOOK_CONFIG_GFX_FORCE_SCREEN_RES_HEIGHT_KEY \
"gfx.force_screen_res.height"
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_FRAMED_VALUE false
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOWED_VALUE false
@@ -103,15 +105,19 @@ void d3d9exhook_config_gfx_init(struct cconfig *config)
config,
D3D9EXHOOK_CONFIG_GFX_FORCE_SCREEN_RES_WIDTH_KEY,
D3D9EXHOOK_CONFIG_GFX_DEFAULT_FORCE_SCREEN_RES_WIDTH_VALUE,
"Force a screen resolution (width), -1 to disable. Use this if the game does not auto "
"detect your monitor's resolution properly, e.g. 1368x768 instead of 1280x720.");
"Force a screen resolution (width), -1 to disable. Use this if the "
"game does not auto "
"detect your monitor's resolution properly, e.g. 1368x768 instead of "
"1280x720.");
cconfig_util_set_int(
config,
D3D9EXHOOK_CONFIG_GFX_FORCE_SCREEN_RES_HEIGHT_KEY,
D3D9EXHOOK_CONFIG_GFX_DEFAULT_FORCE_SCREEN_RES_HEIGHT_VALUE,
"Force a screen resolution (height), -1 to disable. Use this if the game does not auto "
"detect your monitor's resolution properly, e.g. 1368x768 instead of 1280x720.");
"Force a screen resolution (height), -1 to disable. Use this if the "
"game does not auto "
"detect your monitor's resolution properly, e.g. 1368x768 instead of "
"1280x720.");
}
void d3d9exhook_config_gfx_get(

View File

@@ -52,10 +52,8 @@ static HRESULT STDCALL my_EnumAdapterModes(
UINT Mode,
D3DDISPLAYMODE *pMode);
static UINT STDCALL my_GetAdapterModeCount(
IDirect3D9Ex *self,
UINT Adapter,
D3DFORMAT Format);
static UINT STDCALL
my_GetAdapterModeCount(IDirect3D9Ex *self, UINT Adapter, D3DFORMAT Format);
static HRESULT STDCALL my_Direct3DCreate9Ex(UINT sdk_ver, IDirect3D9Ex **api);
@@ -305,7 +303,8 @@ static HRESULT STDCALL my_CreateDeviceEx(
if (fdm) {
log_misc(
"CreateDeviceEx display mode: size %d, width %d, height %d, refresh rate %d, format %d, "
"CreateDeviceEx display mode: size %d, width %d, height %d, "
"refresh rate %d, format %d, "
"scan line ordering %d",
fdm->Size,
fdm->Width,
@@ -318,7 +317,8 @@ static HRESULT STDCALL my_CreateDeviceEx(
log_misc(
"D3D9EX presenter parameters: BackBufferWidth %d, BackBufferHeight "
"%d, BackBufferFormat %d, "
"BackBufferCount %d, MultiSampleType %d, MultiSampleQuality %ld, SwapEffect %d, "
"BackBufferCount %d, MultiSampleType %d, MultiSampleQuality %ld, "
"SwapEffect %d, "
"hDeviceWindow %p, Windowed %d, "
"EnableAutoDepthStencil "
"%d, AutoDepthStencilFormat %d, Flags %lX, "
@@ -343,8 +343,10 @@ static HRESULT STDCALL my_CreateDeviceEx(
adapter = d3d9ex_device_adapter;
}
if (d3d9ex_force_screen_res_width > 0 && d3d9ex_force_screen_res_height > 0) {
log_info("Overriding screen resolution/back buffer of %dx%d -> %dx%d",
if (d3d9ex_force_screen_res_width > 0 &&
d3d9ex_force_screen_res_height > 0) {
log_info(
"Overriding screen resolution/back buffer of %dx%d -> %dx%d",
pp->BackBufferWidth,
pp->BackBufferHeight,
d3d9ex_force_screen_res_width,
@@ -445,7 +447,7 @@ static HRESULT STDCALL my_EnumAdapterModes(
IDirect3D9Ex *real = com_proxy_downcast(self)->real;
HRESULT hr;
if (d3d9ex_device_adapter>= 0) {
if (d3d9ex_device_adapter >= 0) {
Adapter = d3d9ex_device_adapter;
}
@@ -461,15 +463,13 @@ static HRESULT STDCALL my_EnumAdapterModes(
return hr;
}
static UINT STDCALL my_GetAdapterModeCount(
IDirect3D9Ex *self,
UINT Adapter,
D3DFORMAT Format)
static UINT STDCALL
my_GetAdapterModeCount(IDirect3D9Ex *self, UINT Adapter, D3DFORMAT Format)
{
IDirect3D9Ex *real = com_proxy_downcast(self)->real;
UINT res;
if (d3d9ex_device_adapter>= 0) {
if (d3d9ex_device_adapter >= 0) {
Adapter = d3d9ex_device_adapter;
}
@@ -494,14 +494,14 @@ static HRESULT STDCALL my_Direct3DCreate9Ex(UINT sdk_ver, IDirect3D9Ex **api)
hr = real_Direct3DCreate9Ex(sdk_ver, api);
api_ = *api;
hr = com_proxy_wrap(&api_proxy, api_, sizeof(*api_->lpVtbl));
if (hr != S_OK) {
log_warning("Wrapping com proxy failed: %08lx", hr);
return hr;
}
api_vtbl = api_proxy->vptr;
api_vtbl->CreateDeviceEx = my_CreateDeviceEx;
@@ -555,7 +555,8 @@ void d3d9ex_configure(struct d3d9exhook_config_gfx *gfx_config)
d3d9ex_force_screen_res_height = gfx_config->force_screen_res.height;
if (d3d9ex_force_screen_res_width * d3d9ex_force_screen_res_height > 0) {
log_warning("Force screen res: Only one, either width or height, is > 0."
log_warning(
"Force screen res: Only one, either width or height, is > 0."
" Force screen res not activate");
}
}

View File

@@ -34,9 +34,7 @@ static struct ac_io_emu_hdxs com4_hdxs;
static struct ac_io_emu_icca com4_icca[2];
static uint32_t check_panel_light(
const struct ac_io_hdxs_output *output,
uint8_t panel_idx,
uint8_t out_idx)
const struct ac_io_hdxs_output *output, uint8_t panel_idx, uint8_t out_idx)
{
if (output->lights[panel_idx].bit) {
return 1 << out_idx;
@@ -45,7 +43,8 @@ static uint32_t check_panel_light(
}
}
static uint8_t upscale_light(uint8_t in_7bit) {
static uint8_t upscale_light(uint8_t in_7bit)
{
if (in_7bit < 0x10) {
return in_7bit * 2;
} else {
@@ -54,18 +53,24 @@ static uint8_t upscale_light(uint8_t in_7bit) {
}
}
static void lights_dispatcher(
struct ac_io_emu_hdxs *emu, const struct ac_io_message *req)
static void
lights_dispatcher(struct ac_io_emu_hdxs *emu, const struct ac_io_message *req)
{
const struct ac_io_hdxs_output *output = &req->cmd.hdxs_output;
uint32_t lights = 0;
lights |= check_panel_light(output, AC_IO_HDXS_OUT_P1_START, LIGHT_HD_P1_START);
lights |= check_panel_light(output, AC_IO_HDXS_OUT_P1_UP_DOWN, LIGHT_HD_P1_UP_DOWN);
lights |= check_panel_light(output, AC_IO_HDXS_OUT_P1_LEFT_RIGHT, LIGHT_HD_P1_LEFT_RIGHT);
lights |= check_panel_light(output, AC_IO_HDXS_OUT_P2_START, LIGHT_HD_P2_START);
lights |= check_panel_light(output, AC_IO_HDXS_OUT_P2_UP_DOWN, LIGHT_HD_P2_UP_DOWN);
lights |= check_panel_light(output, AC_IO_HDXS_OUT_P2_LEFT_RIGHT, LIGHT_HD_P2_LEFT_RIGHT);
lights |=
check_panel_light(output, AC_IO_HDXS_OUT_P1_START, LIGHT_HD_P1_START);
lights |= check_panel_light(
output, AC_IO_HDXS_OUT_P1_UP_DOWN, LIGHT_HD_P1_UP_DOWN);
lights |= check_panel_light(
output, AC_IO_HDXS_OUT_P1_LEFT_RIGHT, LIGHT_HD_P1_LEFT_RIGHT);
lights |=
check_panel_light(output, AC_IO_HDXS_OUT_P2_START, LIGHT_HD_P2_START);
lights |= check_panel_light(
output, AC_IO_HDXS_OUT_P2_UP_DOWN, LIGHT_HD_P2_UP_DOWN);
lights |= check_panel_light(
output, AC_IO_HDXS_OUT_P2_LEFT_RIGHT, LIGHT_HD_P2_LEFT_RIGHT);
ddr_io_set_lights_hdxs_panel(lights);
@@ -73,9 +78,12 @@ static void lights_dispatcher(
size_t light_idx = i * 3;
// these are 7 bit, upscale them to 8 bit
uint8_t r = upscale_light(output->lights[light_idx + AC_IO_HDXS_RED].analog);
uint8_t g = upscale_light(output->lights[light_idx + AC_IO_HDXS_GREEN].analog);
uint8_t b = upscale_light(output->lights[light_idx + AC_IO_HDXS_BLUE].analog);
uint8_t r =
upscale_light(output->lights[light_idx + AC_IO_HDXS_RED].analog);
uint8_t g =
upscale_light(output->lights[light_idx + AC_IO_HDXS_GREEN].analog);
uint8_t b =
upscale_light(output->lights[light_idx + AC_IO_HDXS_BLUE].analog);
ddr_io_set_lights_hdxs_rgb(i, r, g, b);
}

View File

@@ -72,11 +72,11 @@ static HRESULT STDCALL my_DirectInput8Create(
res = real_DirectInput8Create(
hinst, dwVersion, riidltf, (LPVOID *) &api, punkOuter);
if (res != DI_OK) {
return res;
}
res = com_proxy_wrap(&api_proxy, api, sizeof(*api->lpVtbl));
if (res != S_OK) {

View File

@@ -185,8 +185,7 @@ static void gfx_d3d9_patch_window(struct hook_d3d9_irp *irp)
}
}
static void
gfx_d3d9_fix_window_size_and_pos(struct hook_d3d9_irp *irp)
static void gfx_d3d9_fix_window_size_and_pos(struct hook_d3d9_irp *irp)
{
log_assert(irp);
log_assert(irp->op == HOOK_D3D9_IRP_OP_CREATE_WINDOW_EX);
@@ -215,8 +214,7 @@ gfx_d3d9_fix_window_size_and_pos(struct hook_d3d9_irp *irp)
}
}
static void gfx_d3d9_create_device_apply_window_mode(
struct hook_d3d9_irp *irp)
static void gfx_d3d9_create_device_apply_window_mode(struct hook_d3d9_irp *irp)
{
log_assert(irp);
log_assert(irp->op == HOOK_D3D9_IRP_OP_CTX_CREATE_DEVICE);
@@ -231,8 +229,7 @@ static void gfx_d3d9_create_device_apply_window_mode(
}
}
static void gfx_d3d9_reset_apply_window_mode(
struct hook_d3d9_irp *irp)
static void gfx_d3d9_reset_apply_window_mode(struct hook_d3d9_irp *irp)
{
log_assert(irp);
log_assert(irp->op == HOOK_D3D9_IRP_OP_DEV_RESET);

View File

@@ -64,8 +64,14 @@ void p3io_ddr_init_with_plugs(
memcpy(&p3io_ddr_mcode, mcode, sizeof(struct security_mcode));
memcpy(&p3io_ddr_pcbid, pcbid, sizeof(struct security_id));
memcpy(&p3io_ddr_eamid, eamid, sizeof(struct security_id));
memcpy(&p3io_black_sign_key, black_sign_key, sizeof(struct security_rp_sign_key));
memcpy(&p3io_white_sign_key, white_sign_key, sizeof(struct security_rp_sign_key));
memcpy(
&p3io_black_sign_key,
black_sign_key,
sizeof(struct security_rp_sign_key));
memcpy(
&p3io_white_sign_key,
white_sign_key,
sizeof(struct security_rp_sign_key));
/* COM4 isn't a real COM port, we configure the core P3IO emulator code to
generate IRPs addressed to COM4 and then we possibly intercept them in

View File

@@ -15,9 +15,9 @@
#include "hook/iohook.h"
#include "util/crc.h"
#include "util/fs.h"
#include "util/iobuf.h"
#include "util/log.h"
#include "util/fs.h"
#include "util/str.h"
#define USBMEM_DEVICE_COUNT 2
@@ -95,7 +95,8 @@ void usbmem_init(const char *path_p1, const char *path_p2, const bool enabled)
GetFullPathNameA(path_p2, sizeof(usb_data_path[1]), usb_data_path[1], NULL);
log_misc("USB memory data path (P2): %s", usb_data_path[1]);
if (enabled && !path_exists(usb_data_path[0]) && !path_exists(usb_data_path[1])) {
if (enabled && !path_exists(usb_data_path[0]) &&
!path_exists(usb_data_path[1])) {
log_warning("USB memory data path does not exist, disabling");
usbmem_enabled = false;
}
@@ -177,36 +178,53 @@ static HRESULT usbmem_write(struct irp *irp)
log_assert(irp->write.bytes != NULL);
src = &irp->write;
nbytes = src->nbytes > USBMEM_COMMAND_BUF_SIZE ? USBMEM_COMMAND_BUF_SIZE : src->nbytes;
nbytes = src->nbytes > USBMEM_COMMAND_BUF_SIZE ? USBMEM_COMMAND_BUF_SIZE :
src->nbytes;
memcpy(request, src->bytes, nbytes);
request[nbytes - 1] = '\0'; /* This is always a CR. */
if (!usbmem_pending && target_device_id >= 0 && target_device_id < USBMEM_DEVICE_COUNT && usbmem_state[target_device_id].file_type == USBMEM_FILE_TYPE_READ) {
if (!usbmem_pending && target_device_id >= 0 &&
target_device_id < USBMEM_DEVICE_COUNT &&
usbmem_state[target_device_id].file_type == USBMEM_FILE_TYPE_READ) {
memset(usbmem_response, 0, sizeof(usbmem_response));
// log_misc("Read progress %08x/%08x bytes", usbmem_state[target_device_id].buffer_index, usbmem_state[target_device_id].buffer_len);
// log_misc("Read progress %08x/%08x bytes",
// usbmem_state[target_device_id].buffer_index,
// usbmem_state[target_device_id].buffer_len);
if (usbmem_state[target_device_id].buffer_index < usbmem_state[target_device_id].buffer_len) {
if (usbmem_state[target_device_id].buffer_index <
usbmem_state[target_device_id].buffer_len) {
usbmem_response_length = sizeof(usbmem_response);
usbmem_response[0] = 0x02; // 1 = 0x80 buffer, 2 = 0x400 buffer
usbmem_response[1] = usbmem_state[target_device_id].buffer_frame;
usbmem_response[2] = ~usbmem_response[1];
if (usbmem_state[target_device_id].buffer_frame == 0) {
snprintf(usbmem_response + 4, sizeof(usbmem_response) - 5, "%Iu ", usbmem_state[target_device_id].buffer_len);
snprintf(
usbmem_response + 4,
sizeof(usbmem_response) - 5,
"%zu ",
usbmem_state[target_device_id].buffer_len);
} else {
size_t len = sizeof(usbmem_response) - 5;
if (usbmem_state[target_device_id].buffer_index + len > usbmem_state[target_device_id].buffer_len)
len = usbmem_state[target_device_id].buffer_len - usbmem_state[target_device_id].buffer_index;
if (usbmem_state[target_device_id].buffer_index + len >
usbmem_state[target_device_id].buffer_len)
len = usbmem_state[target_device_id].buffer_len -
usbmem_state[target_device_id].buffer_index;
memcpy(usbmem_response + 3, usbmem_state[target_device_id].buffer + usbmem_state[target_device_id].buffer_index, len);
memcpy(
usbmem_response + 3,
usbmem_state[target_device_id].buffer +
usbmem_state[target_device_id].buffer_index,
len);
usbmem_state[target_device_id].buffer_index += len;
}
usbmem_state[target_device_id].buffer_frame++;
uint16_t crc = crc16_msb(usbmem_response + 3, sizeof(usbmem_response) - 5, 0);
uint16_t crc =
crc16_msb(usbmem_response + 3, sizeof(usbmem_response) - 5, 0);
usbmem_response[sizeof(usbmem_response) - 2] = crc >> 8;
usbmem_response[sizeof(usbmem_response) - 1] = crc & 0xff;
} else {
@@ -217,7 +235,8 @@ static HRESULT usbmem_write(struct irp *irp)
log_misc(">%s", request);
// Try to detect device ID
// The only commands without a device ID are "sver", "start", and "init".
// The only commands without a device ID are "sver", "start", and
// "init".
char target_device_val = request[strlen(request) - 1];
char *target_device_id_ptr = strstr(request, " ");
if (target_device_id_ptr != NULL) {
@@ -237,18 +256,22 @@ static HRESULT usbmem_write(struct irp *irp)
target_device_id = target_device_val == 'b' ? 0 : 1;
if (!usbmem_enabled) {
// Ignore all other USB device specific commands and pretend a device isn't plugged in
// when USB memory emulation is disabled.
// Ignore all other USB device specific commands and pretend a
// device isn't plugged in when USB memory emulation is
// disabled.
str_cpy(usbmem_response, sizeof(usbmem_response), "fail");
} else if (usbmem_state[target_device_id].errored) {
// If the device went through the entire process once and the file didn't exist
// then just force it to be disabled until the game is restarted because otherwise
// it'll get stuck in a loop.
// TODO: This could be better emulated by using a keybind to simulate inserting and
// ejecting the USB drive to additionally clear the error flag.
// If the device went through the entire process once and the
// file didn't exist then just force it to be disabled until the
// game is restarted because otherwise it'll get stuck in a
// loop.
// TODO: This could be better emulated by using a keybind to
// simulate inserting and ejecting the USB drive to additionally
// clear the error flag.
str_cpy(usbmem_response, sizeof(usbmem_response), "fail");
} else if (str_eq(request, "on_a") || str_eq(request, "on_b")) {
usbmem_state[target_device_id].connected = path_exists(usbmem_state[target_device_id].basepath);
usbmem_state[target_device_id].connected =
path_exists(usbmem_state[target_device_id].basepath);
usbmem_state[target_device_id].errored = false;
usbmem_reset_file_state(target_device_id);
@@ -256,21 +279,32 @@ static HRESULT usbmem_write(struct irp *irp)
if (usbmem_state[target_device_id].connected)
str_cpy(usbmem_response, sizeof(usbmem_response), "done");
else
str_cpy(usbmem_response, sizeof(usbmem_response), "not connected");
str_cpy(
usbmem_response,
sizeof(usbmem_response),
"not connected");
} else if (str_eq(request, "offa") || str_eq(request, "offb")) {
if (usbmem_state[target_device_id].connected)
str_cpy(usbmem_response, sizeof(usbmem_response), "done");
else
str_cpy(usbmem_response, sizeof(usbmem_response), "not connected");
str_cpy(
usbmem_response,
sizeof(usbmem_response),
"not connected");
usbmem_state[target_device_id].connected = false;
usbmem_reset_file_state(target_device_id);
} else if (str_eq(request, "opna") || str_eq(request, "opnb")) {
bool basepath_exists = path_exists(usbmem_state[target_device_id].basepath);
bool basepath_exists =
path_exists(usbmem_state[target_device_id].basepath);
if (!usbmem_state[target_device_id].connected || !basepath_exists) {
if (!usbmem_state[target_device_id].connected ||
!basepath_exists) {
usbmem_state[target_device_id].opened = false;
str_cpy(usbmem_response, sizeof(usbmem_response), "not connected");
str_cpy(
usbmem_response,
sizeof(usbmem_response),
"not connected");
} else {
usbmem_state[target_device_id].opened = true;
str_cpy(usbmem_response, sizeof(usbmem_response), "done");
@@ -279,82 +313,132 @@ static HRESULT usbmem_write(struct irp *irp)
if (usbmem_state[target_device_id].opened)
str_cpy(usbmem_response, sizeof(usbmem_response), "done");
else
str_cpy(usbmem_response, sizeof(usbmem_response), "not connected");
str_cpy(
usbmem_response,
sizeof(usbmem_response),
"not connected");
usbmem_state[target_device_id].opened = false;
usbmem_reset_file_state(target_device_id);
} else if (strncmp(request, "cda ", 4) == 0 || strncmp(request, "cdb ", 4) == 0) {
} else if (
strncmp(request, "cda ", 4) == 0 ||
strncmp(request, "cdb ", 4) == 0) {
char *path = request + 4;
if (!usbmem_state[target_device_id].connected || !usbmem_state[target_device_id].opened) {
if (!usbmem_state[target_device_id].connected ||
!usbmem_state[target_device_id].opened) {
str_cpy(usbmem_response, sizeof(usbmem_response), "done");
} else if (path[1] == ':') {
// Absolute path
char temp[MAX_PATH];
snprintf(temp, sizeof(temp), "%s\\%s", usbmem_state[target_device_id].basepath, path + 3);
snprintf(
temp,
sizeof(temp),
"%s\\%s",
usbmem_state[target_device_id].basepath,
path + 3);
if (!path_exists(temp)) {
log_warning("Couldn't find path %s", temp);
str_cpy(usbmem_response, sizeof(usbmem_response), "done");
str_cpy(
usbmem_response, sizeof(usbmem_response), "done");
} else {
log_misc("Changing path to %s", temp);
str_cpy(usbmem_state[target_device_id].path, sizeof(usbmem_state[target_device_id].path), temp);
str_cpy(usbmem_response, sizeof(usbmem_response), "done");
str_cpy(
usbmem_state[target_device_id].path,
sizeof(usbmem_state[target_device_id].path),
temp);
str_cpy(
usbmem_response, sizeof(usbmem_response), "done");
}
} else {
str_cpy(usbmem_response, sizeof(usbmem_response), "fail");
}
} else if (strncmp(request, "rda ", 4) == 0 || strncmp(request, "rdb ", 4) == 0) {
} else if (
strncmp(request, "rda ", 4) == 0 ||
strncmp(request, "rdb ", 4) == 0) {
usbmem_reset_file_state(target_device_id);
if (!usbmem_state[target_device_id].connected || !usbmem_state[target_device_id].opened) {
if (!usbmem_state[target_device_id].connected ||
!usbmem_state[target_device_id].opened) {
str_cpy(usbmem_response, sizeof(usbmem_response), "fail");
} else {
char temp[MAX_PATH] = {0};
char *filename = request + 4;
snprintf(temp, sizeof(temp), "%s\\%s", usbmem_state[target_device_id].path, filename);
snprintf(
temp,
sizeof(temp),
"%s\\%s",
usbmem_state[target_device_id].path,
filename);
if (usbmem_state[target_device_id].buffer) {
free(usbmem_state[target_device_id].buffer);
usbmem_state[target_device_id].buffer = NULL;
}
usbmem_state[target_device_id].file_type = USBMEM_FILE_TYPE_NONE;
usbmem_state[target_device_id].file_type =
USBMEM_FILE_TYPE_NONE;
usbmem_state[target_device_id].buffer_len = 0;
usbmem_state[target_device_id].buffer_index = 0;
usbmem_state[target_device_id].buffer_frame = 0;
memset(usbmem_state[target_device_id].filename, 0, sizeof(usbmem_state[target_device_id].filename));
memset(
usbmem_state[target_device_id].filename,
0,
sizeof(usbmem_state[target_device_id].filename));
if (!path_exists(temp)) {
log_warning("Couldn't find file %s", temp);
str_cpy(usbmem_response, sizeof(usbmem_response), "fail");
str_cpy(
usbmem_response, sizeof(usbmem_response), "fail");
usbmem_state[target_device_id].errored = true;
} else {
bool loaded = file_load(temp, (void**)&usbmem_state[target_device_id].buffer,
&usbmem_state[target_device_id].buffer_len, false);
bool loaded = file_load(
temp,
(void **) &usbmem_state[target_device_id].buffer,
&usbmem_state[target_device_id].buffer_len,
false);
if (loaded) {
log_misc("Reading file %s", temp);
usbmem_state[target_device_id].file_type = USBMEM_FILE_TYPE_READ;
usbmem_state[target_device_id].file_type =
USBMEM_FILE_TYPE_READ;
str_cpy(usbmem_state[target_device_id].filename, sizeof(usbmem_state[target_device_id].filename), filename);
str_cpy(usbmem_response, sizeof(usbmem_response), "start");
str_cpy(
usbmem_state[target_device_id].filename,
sizeof(usbmem_state[target_device_id].filename),
filename);
str_cpy(
usbmem_response,
sizeof(usbmem_response),
"start");
} else {
log_warning("Couldn't read file %s", temp);
str_cpy(usbmem_response, sizeof(usbmem_response), "fail");
str_cpy(
usbmem_response,
sizeof(usbmem_response),
"fail");
usbmem_state[target_device_id].errored = true;
}
}
}
} else if (strncmp(request, "wra ", 4) == 0 || strncmp(request, "wrb ", 4) == 0) {
} else if (
strncmp(request, "wra ", 4) == 0 ||
strncmp(request, "wrb ", 4) == 0) {
// Open file for writing
usbmem_reset_file_state(target_device_id);
str_cpy(usbmem_response, sizeof(usbmem_response), "not supported");
} else if (strncmp(request, "wha ", 4) == 0 || strncmp(request, "whb ", 4) == 0) {
str_cpy(
usbmem_response, sizeof(usbmem_response), "not supported");
} else if (
strncmp(request, "wha ", 4) == 0 ||
strncmp(request, "whb ", 4) == 0) {
// Something relating to writing?
str_cpy(usbmem_response, sizeof(usbmem_response), "not supported");
} else if (strncmp(request, "lma ", 4) == 0 || strncmp(request, "lmb ", 4) == 0) {
str_cpy(
usbmem_response, sizeof(usbmem_response), "not supported");
} else if (
strncmp(request, "lma ", 4) == 0 ||
strncmp(request, "lmb ", 4) == 0) {
// What is "lm"?
str_cpy(usbmem_response, sizeof(usbmem_response), "done");
} else {

View File

@@ -84,8 +84,9 @@ static void my_avs_boot(
char nvram_path[MAX_PATH] = {0};
char raw_path[MAX_PATH] = {0};
// Using the full path as part of the AVS paths seems to break on long paths.
// So instead, just take the launcher folder relative to the main game directory.
// Using the full path as part of the AVS paths seems to break on long
// paths. So instead, just take the launcher folder relative to the main
// game directory.
char *launcher_folder;
ddrhook1_get_launcher_path_parts(NULL, &launcher_folder);
@@ -104,10 +105,8 @@ static void my_avs_boot(
log_misc("avs paths: %s %s\n", nvram_path, raw_path);
avs_boot_replace_property_str(
config, "/fs/nvram/device", nvram_path);
avs_boot_replace_property_str(
config, "/fs/raw/device", raw_path);
avs_boot_replace_property_str(config, "/fs/nvram/device", nvram_path);
avs_boot_replace_property_str(config, "/fs/raw/device", raw_path);
#endif
real_avs_boot(

View File

@@ -26,7 +26,8 @@ void ddrhook1_config_ddrhook1_init(struct cconfig *config)
config,
DDRHOOK1_CONFIG_DDRHOOK1_USE_COM4_EMU_KEY,
DDRHOOK1_CONFIG_DDRHOOK1_DEFAULT_USE_COM4_EMU_VALUE,
"Don't emulate P3IO COM4 and its downstream devices, use the Windows COM4 port instead");
"Don't emulate P3IO COM4 and its downstream devices, use the Windows "
"COM4 port instead");
cconfig_util_set_bool(
config,
DDRHOOK1_CONFIG_DDRHOOK1_STANDARD_DEF_KEY,

View File

@@ -41,8 +41,7 @@ void ddrhook1_config_security_get(
char *tmp_default;
char mcode[9];
tmp_default =
security_mcode_to_str(&security_mcode_ddr_x);
tmp_default = security_mcode_to_str(&security_mcode_ddr_x);
if (!cconfig_util_get_str(
config,

View File

@@ -41,7 +41,7 @@
#include "util/thread.h"
#define DDRHOOK1_INFO_HEADER \
"ddrhook1 for DDR X" \
"ddrhook1 for DDR X" \
", build " __DATE__ " " __TIME__ ", gitrev " STRINGIFY(GITREV)
#define DDRHOOK1_CMD_USAGE \
"Usage: inject.exe ddrhook1.dll <ddr.exe> [options...]"
@@ -53,8 +53,10 @@ static const hook_d3d9_irp_handler_t ddrhook1_d3d9_handlers[] = {
gfx_d3d9_irp_handler,
};
static DWORD STDCALL my_GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize);
static DWORD(STDCALL *real_GetModuleFileNameA)(HMODULE hModule, LPSTR lpFilename, DWORD nSize);
static DWORD STDCALL
my_GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize);
static DWORD(STDCALL *real_GetModuleFileNameA)(
HMODULE hModule, LPSTR lpFilename, DWORD nSize);
static bool ddrhook1_init_check = false;
@@ -144,7 +146,9 @@ my_GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize)
#endif
&security_rp_sign_key_white_eamuse);
extio_init();
usbmem_init(config_ddrhook1.usbmem_path_p1, config_ddrhook1.usbmem_path_p2,
usbmem_init(
config_ddrhook1.usbmem_path_p1,
config_ddrhook1.usbmem_path_p2,
config_ddrhook1.usbmem_enabled);
spike_init();
com4_init();
@@ -189,7 +193,8 @@ BOOL WINAPI DllMain(HMODULE self, DWORD reason, void *ctx)
ddrhook1_master_insert_hooks(NULL);
ddrhook1_filesystem_hook_init();
hook_d3d9_init(ddrhook1_d3d9_handlers, lengthof(ddrhook1_d3d9_handlers));
hook_d3d9_init(
ddrhook1_d3d9_handlers, lengthof(ddrhook1_d3d9_handlers));
}
return TRUE;

View File

@@ -1,8 +1,8 @@
#include <windows.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -14,9 +14,8 @@
#include "util/str.h"
static BOOL STDCALL my_SetCurrentDirectoryA(LPCSTR lpPathName);
static HANDLE STDCALL my_FindFirstFileW(
LPCWSTR lpFileName,
LPWIN32_FIND_DATAA lpFindFileData);
static HANDLE STDCALL
my_FindFirstFileW(LPCWSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData);
static HANDLE STDCALL my_CreateFileW(
LPCWSTR lpFileName,
DWORD dwDesiredAccess,
@@ -30,8 +29,7 @@ static BOOL WINAPI my_CreateDirectoryW(
static BOOL(STDCALL *real_SetCurrentDirectoryA)(LPCSTR lpPathName);
static HANDLE(STDCALL *real_FindFirstFileW)(
LPCWSTR lpFileName,
LPWIN32_FIND_DATAA lpFindFileData);
LPCWSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData);
static HANDLE(STDCALL *real_CreateFileW)(
LPCWSTR lpFileName,
DWORD dwDesiredAccess,
@@ -44,29 +42,25 @@ static BOOL(WINAPI *real_CreateDirectoryW)(
LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes);
static const struct hook_symbol filesystem_hook_syms[] = {
{
.name = "CreateFileW",
.patch = my_CreateFileW,
.link = (void **) &real_CreateFileW
},
{.name = "CreateFileW",
.patch = my_CreateFileW,
.link = (void **) &real_CreateFileW},
{
.name = "SetCurrentDirectoryA",
.patch = my_SetCurrentDirectoryA,
.link = (void **) &real_SetCurrentDirectoryA,
},
{
.name = "FindFirstFileW",
.patch = my_FindFirstFileW,
.link = (void **) &real_FindFirstFileW
},
{
.name = "CreateDirectoryW",
.patch = my_CreateDirectoryW,
.link = (void **) &real_CreateDirectoryW
},
{.name = "FindFirstFileW",
.patch = my_FindFirstFileW,
.link = (void **) &real_FindFirstFileW},
{.name = "CreateDirectoryW",
.patch = my_CreateDirectoryW,
.link = (void **) &real_CreateDirectoryW},
};
void ddrhook1_get_launcher_path_parts(char **output_path, char **output_foldername) {
void ddrhook1_get_launcher_path_parts(
char **output_path, char **output_foldername)
{
char module_path[MAX_PATH];
char launcher_path[MAX_PATH];
@@ -82,7 +76,9 @@ void ddrhook1_get_launcher_path_parts(char **output_path, char **output_folderna
return;
char *filename_ptr = NULL;
if (GetFullPathNameA(module_path, sizeof(launcher_path), launcher_path, &filename_ptr) == 0)
if (GetFullPathNameA(
module_path, sizeof(launcher_path), launcher_path, &filename_ptr) ==
0)
return;
if (filename_ptr != NULL)
@@ -98,7 +94,8 @@ void ddrhook1_get_launcher_path_parts(char **output_path, char **output_folderna
int idx_folder = 0;
for (idx_folder = strlen(launcher_path); idx_folder - 1 > 0; idx_folder--) {
if (launcher_path[idx_folder - 1] == '\\' || launcher_path[idx_folder - 1] == '/') {
if (launcher_path[idx_folder - 1] == '\\' ||
launcher_path[idx_folder - 1] == '/') {
break;
}
}
@@ -109,7 +106,7 @@ void ddrhook1_get_launcher_path_parts(char **output_path, char **output_folderna
if (len < 0)
len = 0;
*output_foldername = (char*)xmalloc(len + 2);
*output_foldername = (char *) xmalloc(len + 2);
memset(*output_foldername, 0, len + 1);
strncpy(*output_foldername, launcher_path + idx_folder, len);
}
@@ -120,7 +117,7 @@ void ddrhook1_get_launcher_path_parts(char **output_path, char **output_folderna
if (len > strlen(launcher_path))
len = strlen(launcher_path);
*output_path = (char*)xmalloc(len + 1);
*output_path = (char *) xmalloc(len + 1);
memset(*output_path, 0, len + 1);
strncpy(*output_path, launcher_path, len);
}
@@ -135,9 +132,12 @@ static wchar_t *ddrhook1_filesystem_get_path(LPCWSTR path)
// log_misc("path: %s", tmp);
// free(tmp);
// Deal with hardcoded paths: D:/HDX, E:/conf, E:/conf/nvram, E:/conf/raw, F:/update, ...
if (wstr_insensitive_eq(path, L"D:/HDX") || wstr_insensitive_eq(path, L"D:\\HDX")
|| wstr_insensitive_eq(path, L"D:/JDX") || wstr_insensitive_eq(path, L"D:\\JDX")) {
// Deal with hardcoded paths: D:/HDX, E:/conf, E:/conf/nvram, E:/conf/raw,
// F:/update, ...
if (wstr_insensitive_eq(path, L"D:/HDX") ||
wstr_insensitive_eq(path, L"D:\\HDX") ||
wstr_insensitive_eq(path, L"D:/JDX") ||
wstr_insensitive_eq(path, L"D:\\JDX")) {
char *_new_path;
ddrhook1_get_launcher_path_parts(&_new_path, NULL);
@@ -145,8 +145,10 @@ static wchar_t *ddrhook1_filesystem_get_path(LPCWSTR path)
new_path = str_widen(_new_path);
return new_path;
}
} else if (wcslen(path) >= 7 && (wcsnicmp(path, L"E:/conf", 7) == 0
|| wcsnicmp(path, L"E:\\conf", 7) == 0)) {
} else if (
wcslen(path) >= 7 &&
(wcsnicmp(path, L"E:/conf", 7) == 0 ||
wcsnicmp(path, L"E:\\conf", 7) == 0)) {
char *launcher_folder;
wchar_t *sub_path;
@@ -155,15 +157,17 @@ static wchar_t *ddrhook1_filesystem_get_path(LPCWSTR path)
if (sub_path && launcher_folder) {
wchar_t *launcher_folder_w = str_widen(launcher_folder);
new_path = (wchar_t*)xmalloc(MAX_PATH * sizeof(wchar_t));
swprintf(new_path, MAX_PATH, L"%s\\%s", launcher_folder_w, sub_path);
new_path = (wchar_t *) xmalloc(MAX_PATH * sizeof(wchar_t));
swprintf(
new_path, MAX_PATH, L"%s\\%s", launcher_folder_w, sub_path);
free(launcher_folder_w);
return new_path;
}
} else if (wstr_insensitive_eq(path, L"F:/update")
|| wstr_insensitive_eq(path, L"F:\\update")
|| wstr_insensitive_eq(path, L".\\F:/update")
|| wstr_insensitive_eq(path, L".\\F:\\update")) {
} else if (
wstr_insensitive_eq(path, L"F:/update") ||
wstr_insensitive_eq(path, L"F:\\update") ||
wstr_insensitive_eq(path, L".\\F:/update") ||
wstr_insensitive_eq(path, L".\\F:\\update")) {
char *launcher_folder;
wchar_t *sub_path;
@@ -172,33 +176,40 @@ static wchar_t *ddrhook1_filesystem_get_path(LPCWSTR path)
if (sub_path && launcher_folder) {
wchar_t *launcher_folder_w = str_widen(launcher_folder);
new_path = (wchar_t*)xmalloc(MAX_PATH * sizeof(wchar_t));
swprintf(new_path, MAX_PATH, L"%s\\%s", launcher_folder_w, sub_path);
new_path = (wchar_t *) xmalloc(MAX_PATH * sizeof(wchar_t));
swprintf(
new_path, MAX_PATH, L"%s\\%s", launcher_folder_w, sub_path);
free(launcher_folder_w);
return new_path;
}
} else if (wcslen(path) >= 24 && (wcsnicmp(path, L"D:/JDX/JDX-001/contents/", 24) == 0
|| wcsnicmp(path, L"D:\\JDX\\JDX-001\\contents\\", 24) == 0)) {
} else if (
wcslen(path) >= 24 &&
(wcsnicmp(path, L"D:/JDX/JDX-001/contents/", 24) == 0 ||
wcsnicmp(path, L"D:\\JDX\\JDX-001\\contents\\", 24) == 0)) {
char *content_path;
ddrhook1_get_launcher_path_parts(&content_path, NULL);
if (content_path) {
wchar_t *content_path_w = str_widen(content_path);
new_path = (wchar_t*)xmalloc(MAX_PATH * sizeof(wchar_t));
new_path = (wchar_t *) xmalloc(MAX_PATH * sizeof(wchar_t));
swprintf(new_path, MAX_PATH, L"%s\\%s", content_path_w, path + 24);
free(content_path_w);
return new_path;
}
} else if (wcslen(path) >= 7 && (wcsnicmp(path, L"D:/HDX/", 7) == 0 || wcsnicmp(path, L"D:\\HDX\\", 7) == 0
|| wcsnicmp(path, L"D:/JDX/", 7) == 0 || wcsnicmp(path, L"D:\\JDX\\", 7) == 0)) {
} else if (
wcslen(path) >= 7 &&
(wcsnicmp(path, L"D:/HDX/", 7) == 0 ||
wcsnicmp(path, L"D:\\HDX\\", 7) == 0 ||
wcsnicmp(path, L"D:/JDX/", 7) == 0 ||
wcsnicmp(path, L"D:\\JDX\\", 7) == 0)) {
char *content_path;
ddrhook1_get_launcher_path_parts(&content_path, NULL);
if (content_path) {
wchar_t *content_path_w = str_widen(content_path);
new_path = (wchar_t*)xmalloc(MAX_PATH * sizeof(wchar_t));
new_path = (wchar_t *) xmalloc(MAX_PATH * sizeof(wchar_t));
swprintf(new_path, MAX_PATH, L"%s\\%s", content_path_w, path + 7);
free(content_path_w);
return new_path;
@@ -225,7 +236,10 @@ static BOOL STDCALL my_SetCurrentDirectoryA(LPCSTR lpPathName)
if (new_path != NULL) {
bool r = real_SetCurrentDirectoryA(new_path);
log_misc("SetCurrentDirectoryA remapped path %s -> %s", lpPathName, new_path);
log_misc(
"SetCurrentDirectoryA remapped path %s -> %s",
lpPathName,
new_path);
free(new_path);
return r;
}
@@ -233,16 +247,13 @@ static BOOL STDCALL my_SetCurrentDirectoryA(LPCSTR lpPathName)
return real_SetCurrentDirectoryA(lpPathName);
}
static HANDLE STDCALL my_FindFirstFileW(
LPCWSTR lpFileName,
LPWIN32_FIND_DATAA lpFindFileData)
static HANDLE STDCALL
my_FindFirstFileW(LPCWSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData)
{
wchar_t *new_path = ddrhook1_filesystem_get_path(lpFileName);
if (new_path) {
HANDLE r = real_FindFirstFileW(
new_path,
lpFindFileData);
HANDLE r = real_FindFirstFileW(new_path, lpFindFileData);
char *tmp;
wstr_narrow(new_path, &tmp);
@@ -253,9 +264,7 @@ static HANDLE STDCALL my_FindFirstFileW(
return r;
}
return real_FindFirstFileW(
lpFileName,
lpFindFileData);
return real_FindFirstFileW(lpFileName, lpFindFileData);
}
static HANDLE STDCALL my_CreateFileW(
@@ -321,7 +330,10 @@ BOOL WINAPI my_CreateDirectoryW(
void ddrhook1_filesystem_hook_init()
{
hook_table_apply(
NULL, "kernel32.dll", filesystem_hook_syms, lengthof(filesystem_hook_syms));
NULL,
"kernel32.dll",
filesystem_hook_syms,
lengthof(filesystem_hook_syms));
log_info("Inserted filesystem hooks");
}

View File

@@ -75,7 +75,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param)
case 'a':
/* Specify a USB memory path for P1 */
if (i + 1 < argc) {
strcpy(usbmem_data_path_p1, argv[i+1]);
strcpy(usbmem_data_path_p1, argv[i + 1]);
usbmem_enabled = true;
i++; // Move forward one to skip the path parameter
}
@@ -85,7 +85,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param)
case 'b':
/* Specify a USB memory path for P2 */
if (i + 1 < argc) {
strcpy(usbmem_data_path_p2, argv[i+1]);
strcpy(usbmem_data_path_p2, argv[i + 1]);
usbmem_enabled = true;
i++; // Move forward one to skip the path parameter
}
@@ -134,7 +134,8 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param)
eam_io_set_loggers(
log_body_misc, log_body_info, log_body_warning, log_body_fatal);
ok = eam_io_init(avs_thread_create, avs_thread_join, avs_thread_destroy);
ok =
eam_io_init(avs_thread_create, avs_thread_join, avs_thread_destroy);
if (!ok) {
return false;

View File

@@ -16,7 +16,6 @@ static HMODULE(STDCALL *real_LoadLibraryA)(const char *name);
static HMODULE STDCALL my_LoadLibraryA(const char *name);
static const hook_d3d9_irp_handler_t ddrhook2_d3d9_handlers[] = {
gfx_d3d9_irp_handler,
};

View File

@@ -43,20 +43,49 @@ static const struct ddr_io_smx_pad_map ddr_io_smx_pad_map[] = {
#define DDR_IO_SMX_LIGHT_VALUES_PER_PANEL 75
#define DDR_IO_SMX_NUMBER_OF_PANELS 18
#define DDR_IO_SMX_TOTAL_LIGHT_VALUES DDR_IO_SMX_LIGHT_VALUES_PER_PANEL * DDR_IO_SMX_NUMBER_OF_PANELS
#define DDR_IO_SMX_TOTAL_LIGHT_VALUES \
DDR_IO_SMX_LIGHT_VALUES_PER_PANEL *DDR_IO_SMX_NUMBER_OF_PANELS
static const struct ddr_io_smx_light_map ddr_io_smx_light_map[] = {
/* Light L/R blue and U/D red to match DDR pad color scheme */
{1 << LIGHT_P1_UP, DDR_IO_SMX_LIGHT_VALUES_PER_PANEL * 1, 0xFF, 0x00, 0x00},
{1 << LIGHT_P1_LEFT, DDR_IO_SMX_LIGHT_VALUES_PER_PANEL * 3, 0x00, 0x00, 0xFF},
{1 << LIGHT_P1_RIGHT, DDR_IO_SMX_LIGHT_VALUES_PER_PANEL * 5, 0x00, 0x00, 0xFF},
{1 << LIGHT_P1_DOWN, DDR_IO_SMX_LIGHT_VALUES_PER_PANEL * 7, 0xFF, 0x00, 0x00},
{1 << LIGHT_P1_LEFT,
DDR_IO_SMX_LIGHT_VALUES_PER_PANEL * 3,
0x00,
0x00,
0xFF},
{1 << LIGHT_P1_RIGHT,
DDR_IO_SMX_LIGHT_VALUES_PER_PANEL * 5,
0x00,
0x00,
0xFF},
{1 << LIGHT_P1_DOWN,
DDR_IO_SMX_LIGHT_VALUES_PER_PANEL * 7,
0xFF,
0x00,
0x00},
{1 << LIGHT_P2_UP, DDR_IO_SMX_LIGHT_VALUES_PER_PANEL * 10, 0xFF, 0x00, 0x00},
{1 << LIGHT_P2_LEFT, DDR_IO_SMX_LIGHT_VALUES_PER_PANEL * 12, 0x00, 0x00, 0xFF},
{1 << LIGHT_P2_RIGHT, DDR_IO_SMX_LIGHT_VALUES_PER_PANEL * 14, 0x00, 0x00, 0xFF},
{1 << LIGHT_P2_DOWN, DDR_IO_SMX_LIGHT_VALUES_PER_PANEL * 16, 0xFF, 0x00, 0x00},
{1 << LIGHT_P2_UP,
DDR_IO_SMX_LIGHT_VALUES_PER_PANEL * 10,
0xFF,
0x00,
0x00},
{1 << LIGHT_P2_LEFT,
DDR_IO_SMX_LIGHT_VALUES_PER_PANEL * 12,
0x00,
0x00,
0xFF},
{1 << LIGHT_P2_RIGHT,
DDR_IO_SMX_LIGHT_VALUES_PER_PANEL * 14,
0x00,
0x00,
0xFF},
{1 << LIGHT_P2_DOWN,
DDR_IO_SMX_LIGHT_VALUES_PER_PANEL * 16,
0xFF,
0x00,
0x00},
};
static _Atomic uint32_t ddr_io_smx_pad_state[2];

View File

@@ -8,9 +8,9 @@
#include <stdint.h>
#include <stdio.h>
#include "aciomgr/manager.h"
#include "aciodrv/device.h"
#include "aciodrv/icca.h"
#include "aciomgr/manager.h"
#include "bemanitools/eamio.h"
@@ -23,22 +23,23 @@
#define NUMBER_OF_EMULATED_READERS 2
#define INVALID_NODE_ID -1
static const uint8_t eam_io_keypad_mappings[16] = {EAM_IO_KEYPAD_DECIMAL,
EAM_IO_KEYPAD_3,
EAM_IO_KEYPAD_6,
EAM_IO_KEYPAD_9,
0xFF,
0xFF,
0xFF,
0xFF,
EAM_IO_KEYPAD_0,
EAM_IO_KEYPAD_1,
EAM_IO_KEYPAD_4,
EAM_IO_KEYPAD_7,
EAM_IO_KEYPAD_00,
EAM_IO_KEYPAD_2,
EAM_IO_KEYPAD_5,
EAM_IO_KEYPAD_8};
static const uint8_t eam_io_keypad_mappings[16] = {
EAM_IO_KEYPAD_DECIMAL,
EAM_IO_KEYPAD_3,
EAM_IO_KEYPAD_6,
EAM_IO_KEYPAD_9,
0xFF,
0xFF,
0xFF,
0xFF,
EAM_IO_KEYPAD_0,
EAM_IO_KEYPAD_1,
EAM_IO_KEYPAD_4,
EAM_IO_KEYPAD_7,
EAM_IO_KEYPAD_00,
EAM_IO_KEYPAD_2,
EAM_IO_KEYPAD_5,
EAM_IO_KEYPAD_8};
static struct ac_io_icca_state eam_io_icca_state[NUMBER_OF_EMULATED_READERS];
@@ -119,7 +120,8 @@ bool eam_io_init(
for (uint8_t i = 0; i < NUMBER_OF_EMULATED_READERS; i++) {
icca_node_id[i] = INVALID_NODE_ID;
for (uint8_t nid = 0; nid < aciomgr_get_node_count(acio_manager_ctx); ++nid) {
for (uint8_t nid = 0; nid < aciomgr_get_node_count(acio_manager_ctx);
++nid) {
if (check_if_icca(nid)) {
bool existing_reader = false;
@@ -139,7 +141,8 @@ bool eam_io_init(
icca_is_slotted[i] = aciodrv_icca_is_slotted(device, nid);
icca_last_nonbusy_state[i] = 0;
log_misc("ICC reader %d is_slotted: %d", nid, icca_is_slotted[i]);
log_misc(
"ICC reader %d is_slotted: %d", nid, icca_is_slotted[i]);
if (!aciodrv_icca_init(device, icca_node_id[i])) {
log_warning("Initializing icca %d failed", i);
@@ -187,25 +190,28 @@ uint8_t eam_io_get_sensor_state(uint8_t unit_no)
if (icca_is_slotted[unit_no]) {
if ((eam_io_icca_state[unit_no].sensor_state &
AC_IO_ICCA_SENSOR_MASK_BACK_ON) > 0) {
AC_IO_ICCA_SENSOR_MASK_BACK_ON) > 0) {
sensors |= (1 << EAM_IO_SENSOR_BACK);
}
if ((eam_io_icca_state[unit_no].sensor_state &
AC_IO_ICCA_SENSOR_MASK_FRONT_ON) > 0) {
AC_IO_ICCA_SENSOR_MASK_FRONT_ON) > 0) {
sensors |= (1 << EAM_IO_SENSOR_FRONT);
}
} else {
// wavepass readers always report (EAM_IO_SENSOR_BACK + EAM_IO_SENSOR_FRONT) + type
// but because we can't report status_code back directly
// and libacio actually just ignores the sensor_state other then the type
// we just return this state like we're a slotted reader so the emulation takes card of it
if (eam_io_icca_state[unit_no].status_code == AC_IO_ICCA_STATUS_GOT_UID) {
// wavepass readers always report (EAM_IO_SENSOR_BACK +
// EAM_IO_SENSOR_FRONT) + type but because we can't report status_code
// back directly and libacio actually just ignores the sensor_state
// other then the type we just return this state like we're a slotted
// reader so the emulation takes card of it
if (eam_io_icca_state[unit_no].status_code ==
AC_IO_ICCA_STATUS_GOT_UID) {
sensors |= (1 << EAM_IO_SENSOR_BACK);
sensors |= (1 << EAM_IO_SENSOR_FRONT);
}
// continue reporting last state during busy
if (eam_io_icca_state[unit_no].status_code == AC_IO_ICCA_STATUS_BUSY_NEW) {
if (eam_io_icca_state[unit_no].status_code ==
AC_IO_ICCA_STATUS_BUSY_NEW) {
sensors = icca_last_nonbusy_state[unit_no];
} else {
icca_last_nonbusy_state[unit_no] = sensors;
@@ -243,18 +249,28 @@ bool eam_io_card_slot_cmd(uint8_t unit_no, uint8_t cmd)
switch (cmd) {
case EAM_IO_CARD_SLOT_CMD_CLOSE:
response = aciodrv_icca_set_state(
device, icca_node_id[unit_no], AC_IO_ICCA_SLOT_STATE_CLOSE, NULL);
device,
icca_node_id[unit_no],
AC_IO_ICCA_SLOT_STATE_CLOSE,
NULL);
case EAM_IO_CARD_SLOT_CMD_OPEN:
response = aciodrv_icca_set_state(
device, icca_node_id[unit_no], AC_IO_ICCA_SLOT_STATE_OPEN, NULL);
device,
icca_node_id[unit_no],
AC_IO_ICCA_SLOT_STATE_OPEN,
NULL);
case EAM_IO_CARD_SLOT_CMD_EJECT:
response = aciodrv_icca_set_state(
device, icca_node_id[unit_no], AC_IO_ICCA_SLOT_STATE_EJECT, NULL);
device,
icca_node_id[unit_no],
AC_IO_ICCA_SLOT_STATE_EJECT,
NULL);
case EAM_IO_CARD_SLOT_CMD_READ:
response = aciodrv_icca_read_card(device, icca_node_id[unit_no], NULL) &&
response =
aciodrv_icca_read_card(device, icca_node_id[unit_no], NULL) &&
aciodrv_icca_get_state(
device, icca_node_id[unit_no], &eam_io_icca_state[unit_no]);
@@ -281,17 +297,18 @@ bool eam_io_poll(uint8_t unit_no)
if (response && !icca_is_slotted[unit_no]) {
// we handle wavepass a bit differently to handle polling felica
if (eam_io_icca_state[unit_no].status_code != AC_IO_ICCA_STATUS_BUSY_NEW) {
if (eam_io_icca_state[unit_no].status_code !=
AC_IO_ICCA_STATUS_BUSY_NEW) {
++icca_poll_counter[unit_no];
}
// we must manually call this every few polls to actually update the felica state
// we don't do it every poll, since card polling isn't that time sensitive of an operation
// libacio does it every 5ish polls after the last AC_IO_ICCA_STATUS_BUSY_NEW message
// we must manually call this every few polls to actually update the
// felica state we don't do it every poll, since card polling isn't that
// time sensitive of an operation libacio does it every 5ish polls after
// the last AC_IO_ICCA_STATUS_BUSY_NEW message
if (icca_poll_counter[unit_no] >= IDLE_RESPONSES_BETWEEN_FELICA_POLLS) {
response = aciodrv_icca_poll_felica(
aciomgr_port_checkout(acio_manager_ctx),
icca_node_id[unit_no]);
aciomgr_port_checkout(acio_manager_ctx), icca_node_id[unit_no]);
aciomgr_port_checkin(acio_manager_ctx);
icca_poll_counter[unit_no] = 0;

View File

@@ -333,7 +333,7 @@ bool eam_impl_get_sensor_state(struct eam *eam, uint8_t unit_no)
}
if (unit->sensor_hot) {
if ((int32_t)(unit->sensor_time - now) > 0) {
if ((int32_t) (unit->sensor_time - now) > 0) {
result = true;
} else {
unit->sensor_time = 0;

View File

@@ -1,7 +1,7 @@
#ifndef EZUSB_EMU_CONF_H
#define EZUSB_EMU_CONF_H
//#define EZUSB_EMU_DEBUG_DUMP
//#define EZUSB_EMU_FW_DUMP
// #define EZUSB_EMU_DEBUG_DUMP
// #define EZUSB_EMU_FW_DUMP
#endif

View File

@@ -2,10 +2,11 @@
const struct ezusb_emu_desc_device ezusb_emu_desc_device = {
.setupapi =
{.device_guid = {0xAE18AA60,
0x7F6A,
0x11D4,
{0x97, 0xDD, 0x00, 0x01, 0x02, 0x29, 0xB9, 0x59}},
{.device_guid =
{0xAE18AA60,
0x7F6A,
0x11D4,
{0x97, 0xDD, 0x00, 0x01, 0x02, 0x29, 0xB9, 0x59}},
.device_desc = "Cypress EZ-USB (2235) - EEPROM missing",
.device_path = "\\\\.\\Ezusb-0"},
.vid = 0x0547,

View File

@@ -28,6 +28,10 @@
#include "util/log.h"
#include "util/str.h"
// The max buffer size in iidx's ezusb client library is 4096 for the initial
// firmware download.
#define MAX_IOCTL_BUFFER_SIZE 4096
static HRESULT ezusb_get_device_descriptor(struct irp *irp);
static HRESULT ezusb_vendor_req(struct irp *irp);
static HRESULT ezusb_upload_fw(struct irp *irp);
@@ -115,43 +119,116 @@ static HRESULT ezusb_open(struct irp *irp)
static HRESULT ezusb_ioctl(struct irp *irp)
{
HRESULT res;
// Stack alloc'd and fixed sized buffers to avoid processing costs with
// allocations. Ensure buffers are large enough for any operation
uint8_t write_buffer_local[MAX_IOCTL_BUFFER_SIZE];
uint8_t read_buffer_local[MAX_IOCTL_BUFFER_SIZE];
uint8_t *write_buffer_orig;
uint8_t *read_buffer_orig;
// Save original buffer that is owned and managed by the caller/the game
// Do NOT read/write these buffers directly because the game's ezusb
// interface library does not access to them entirely thread safe.
// This causes verious odd bugs due to data read/write inconsistencies
// between data access and modification by at least two different threads.
//
// The game's ezusb (client) library was created on a platform with no
// true multi-core processing (Pentium 4 era of hardware). However, the
// developers utilized threading primitives of the Win32 API to ensure
// a high rate of data updates to reduce input latency. This was architected
// using a dedicated polling thread in the ezusb client library that drives
// the IO polling on a high update rate. The captured data was stored in
// a shared buffer that is also accessible by other threads from the main
// game binary. However, the data access to the same shared buffer with the
// polling backend is not synchronized
//
// Thus, the various odd and flaky ezusb communication bugs we see on
// modern, and true multi-core hardware, are the concurrency management
// mistakes that are now creeping up. The developers back then had no
// proper means to test these due to the lack of hardware capabilities.
// Save the IO buffer that is used by the ezusb client backend and shared
// with the game's main thread
write_buffer_orig = (uint8_t *) irp->write.bytes;
read_buffer_orig = irp->read.bytes;
// Prepare our own thread locally managed and non shared buffers for any
// further data operations that are part of the ezusb emulation stack
memset(write_buffer_local, 0, sizeof(write_buffer_local));
memset(read_buffer_local, 0, sizeof(read_buffer_local));
// Sanity check and visibility, in case this ever overflows
if (irp->write.nbytes > sizeof(write_buffer_local)) {
log_fatal(
"Insufficient local write buffer available for ioctl, local "
"size %d, ioctl buffer size %d",
sizeof(write_buffer_local),
irp->write.nbytes);
}
if (irp->read.nbytes > sizeof(read_buffer_local)) {
log_fatal(
"Insufficient local read buffer available for ioctl, local "
"size %d, ioctl buffer size %d",
sizeof(read_buffer_local),
irp->read.nbytes);
}
// Temporarily hook our local buffers to the irp
irp->write.bytes = write_buffer_local;
irp->read.bytes = read_buffer_local;
// Move data from the shared buffers to the local one
// Probably the "most atomic way possible" to have the least amount of
// overlap with the game's shared buffer
memcpy(write_buffer_local, write_buffer_orig, irp->write.nbytes);
memcpy(read_buffer_local, read_buffer_orig, irp->read.nbytes);
/* For debugging */
#ifdef EZUSB_EMU_DEBUG_DUMP
/* For debugging */
ezusb_emu_util_log_usb_msg(
"BEFORE",
irp->ioctl,
irp->read.bytes,
irp->read.nbytes,
irp->read.bytes,
irp->read.nbytes,
irp->write.bytes,
irp->write.nbytes);
read_buffered.bytes,
read_buffered.nbytes,
read_buffered.bytes,
read_buffered.nbytes,
write_buffered.bytes,
write_buffered.nbytes);
#endif
/* Cases are listed in order of first receipt */
switch (irp->ioctl) {
case IOCTL_Ezusb_GET_DEVICE_DESCRIPTOR:
return ezusb_get_device_descriptor(irp);
res = ezusb_get_device_descriptor(irp);
break;
case IOCTL_Ezusb_VENDOR_REQUEST:
return ezusb_vendor_req(irp);
res = ezusb_vendor_req(irp);
break;
case IOCTL_EZUSB_ANCHOR_DOWNLOAD:
return ezusb_upload_fw(irp);
res = ezusb_upload_fw(irp);
break;
case IOCTL_EZUSB_BULK_READ:
/* Misnomer: can be bulk or interrupt. */
return ezusb_pipe_read(irp);
res = ezusb_pipe_read(irp);
break;
case IOCTL_EZUSB_BULK_WRITE:
/* Ditto. */
return ezusb_pipe_write(irp);
res = ezusb_pipe_write(irp);
break;
default:
log_warning("Unknown ioctl %08x", irp->ioctl);
return E_INVALIDARG;
res = E_INVALIDARG;
}
#ifdef EZUSB_EMU_DEBUG_DUMP
@@ -159,13 +236,24 @@ static HRESULT ezusb_ioctl(struct irp *irp)
ezusb_emu_util_log_usb_msg(
"AFTER",
irp->ioctl,
irp->read.bytes,
irp->read.nbytes,
irp->read.bytes,
irp->read.nbytes,
irp->write.bytes,
irp->write.nbytes);
read_buffered.bytes,
read_buffered.nbytes,
read_buffered.bytes,
read_buffered.nbytes,
write_buffered.bytes,
write_buffered.nbytes);
#endif
// Move data back to shared IO buffer. Again, keep this keeps the access
// overlap as minimal as possible
memcpy(write_buffer_orig, write_buffer_local, irp->write.nbytes);
memcpy(read_buffer_orig, read_buffer_local, irp->read.nbytes);
// Re-store the original irp buffer state
irp->write.bytes = (const uint8_t *) write_buffer_orig;
irp->read.bytes = read_buffer_orig;
return res;
}
/*
* USB TRANSFER LAYER

View File

@@ -16,8 +16,10 @@
static struct security_mcode ezusb_iidx_emu_node_security_plug_boot_version;
static uint32_t ezusb_iidx_emu_node_security_plug_boot_seeds[3];
static struct security_rp_sign_key ezusb_iidx_emu_node_security_plug_black_sign_key;
static struct security_rp_sign_key ezusb_iidx_emu_node_security_plug_white_sign_key;
static struct security_rp_sign_key
ezusb_iidx_emu_node_security_plug_black_sign_key;
static struct security_rp_sign_key
ezusb_iidx_emu_node_security_plug_white_sign_key;
static struct security_mcode ezusb_iidx_emu_node_security_plug_black_mcode;
static struct security_mcode ezusb_iidx_emu_node_security_plug_white_mcode;
@@ -179,16 +181,21 @@ uint8_t ezusb_iidx_emu_node_security_plug_process_cmd_v1(
/* TODO ? */
return EZUSB_IIDX_SECPLUG_CMD_STATUS_V1_OK;
case EZUSB_IIDX_SECPLUG_CMD_V1_SELECT_BLACK_DONGLE:
log_misc("EZUSB_IIDX_SECPLUG_CMD_V1_SELECT_BLACK_DONGLE");
// Black dongle
case EZUSB_IIDX_SECPLUG_CMD_V1_SELECT_DONGLE_1:
log_misc("EZUSB_IIDX_SECPLUG_CMD_V1_SELECT_DONGLE_1");
ezusb_iidx_emu_node_security_plug_active_dongle_slot =
EZUSB_IIDX_SECPLUG_DONGLE_SLOT_BLACK;
return EZUSB_IIDX_SECPLUG_CMD_STATUS_V1_OK;
case EZUSB_IIDX_SECPLUG_CMD_V1_SELECT_WHITE_DONGLE:
log_misc("EZUSB_IIDX_SECPLUG_CMD_V1_SELECT_WHITE_DONGLE");
// Used by D01 to also address black dongle?
// Note that iidx 9 to 13 never had a white dongle
// The white dongle/separate eamuse license key was introduced
// with iidx 14
case EZUSB_IIDX_SECPLUG_CMD_V1_SELECT_DONGLE_2:
log_misc("EZUSB_IIDX_SECPLUG_CMD_V1_SELECT_DONGLE_2");
ezusb_iidx_emu_node_security_plug_active_dongle_slot =
EZUSB_IIDX_SECPLUG_DONGLE_SLOT_WHITE;
EZUSB_IIDX_SECPLUG_DONGLE_SLOT_BLACK;
return EZUSB_IIDX_SECPLUG_CMD_STATUS_V1_OK;
default:
@@ -223,8 +230,9 @@ uint8_t ezusb_iidx_emu_node_security_plug_process_cmd_v2(
// pop'n music only ever uses slot 2 (white) and slot 4 (black).
// If the configuration does not match then it will error out.
// IIDX uses slots 2 and 3 and detects what is plugged into each slot so ordering isn't important.
// IIDX also reads slot 1's data section but doesn't care what dongle it is?
// IIDX uses slots 2 and 3 and detects what is plugged into each slot so
// ordering isn't important. IIDX also reads slot 1's data section but
// doesn't care what dongle it is?
case EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_1:
log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_1");
ezusb_iidx_emu_node_security_plug_active_dongle_slot =

View File

@@ -12,8 +12,8 @@
#include "ezusb-emu/node-security-plug.h"
#include "ezusb-emu/node-sram.h"
#include "ezusb-emu/node-wdt.h"
#include "ezusb-emu/nodes.h"
#include "ezusb-emu/node.h"
#include "ezusb-emu/nodes.h"
/* All IIDX games */
const struct ezusb_iidx_emu_node ezusb_iidx_emu_node_coin = {

Some files were not shown because too many files have changed in this diff Show More