Compare commits

...

91 Commits
v5.29 ... 5.33

Author SHA1 Message Date
icex2
e6766d4a3b Update readme with supported games, iidx27 2020-10-27 20:10:10 +01:00
icex2
843d78bc4b Update changelog for 5.33 release 2020-10-27 19:51:48 +01:00
Will Xyen
0792b29f3d iidxhook9: Add iidxhook support for versions that use dx9ex and some other features 2020-10-24 12:17:55 -07:00
Will Xyen
e1d4810743 mempatch-hook: fix CRLF 2020-10-24 11:15:58 -07:00
Will Xyen
2110abc269 [avs] add avs_is_active import 2020-10-23 17:31:49 -07:00
icex2
fc22f76988 doc: Add missing supported iidx version to iidxhook8 2020-10-20 23:45:19 +02:00
Will Xyen
3d4df4cd64 [memfile] Add support for faking files in memory 2020-10-18 14:46:34 -07:00
Will Xyen
be5a773cb7 [iohook] Fix iohook_init race condition 2020-10-18 14:45:49 -07:00
Will Xyen
3ed6ac6290 [tools] Add x64 mempatch-hook 2020-10-06 20:01:41 -07:00
icex2
e49149b03d Update README.md, add pipeline status 2020-10-03 20:38:05 +00:00
Will Xyen
af507e6dcb vigem-sdvxio: Remove unused header 2020-09-27 18:59:24 -07:00
Will Xyen
a9ebc30ea7 vigem-sdvxio: Add relative mode and address comments 2020-09-26 22:54:12 -07:00
Will Xyen
4f3135439d vigem-sdvxio: Add readme 2020-09-13 20:16:37 -07:00
Will Xyen
2d1c09d4e6 sdvxhook: code-format 2020-09-13 19:46:16 -07:00
Will Xyen
164d56b6eb vigem-sdvxio: Add implementation 2020-09-13 19:45:52 -07:00
Will Xyen
1712f10f66 minor bugfixes 2020-09-12 07:53:00 -07:00
Will T
128496901e Add jbiotest for testing jubeat IO impls 2020-09-12 09:12:35 +00:00
icex2
65a45740d2 launcher: Log OS version on startup 2020-09-02 22:04:55 +02:00
icex2
8bd0f44e24 inject: Log OS version on startup 2020-09-02 22:04:55 +02:00
icex2
7733912ae2 util: Add OS module to get version information of Windows
Data we always need when things go wrong, log it on boot.
2020-09-02 22:04:53 +02:00
icex2
55c9f5a521 hooks for inject: Fix log output in DllMain
With the new inject tool, the output of OutputDebugString is
available on console and file logging.
2020-09-02 22:03:26 +02:00
icex2
917dc88826 util/log: Remove log_error, replace occurances with log_warning
log_error was using the log_writer_fatal impl which conflicts with
how this is used on AVS. Therefore, achieve a visible "error"
message in inject by using log_warning + ERROR string in the message
2020-09-02 19:53:07 +00:00
icex2
475d438ec7 inject/debugger: Avoid code dupe 2020-09-02 19:53:07 +00:00
icex2
f23d3531a2 util/signal: Expose signal_exception_code_to_str
Can be re-used in inject/debugger to avoid code duplication
2020-09-02 19:53:07 +00:00
icex2
32c3428c59 inject/logger: Add timestamps to log messages 2020-09-02 19:53:07 +00:00
icex2
ee034a1f08 inject: Fix windows psapi mess by explicitly defining version
Otherwise, the compiler does not link the correct version of that
API. See the requirements section at the bottom of the page here:
https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmodulebasenamea
2020-09-02 19:53:06 +00:00
icex2
54b321c7d9 inject: Major refactoring
This addresses one major issue and multiple minor ones:
Major:
Inject's debugger is not attached to the process before
injecting DLL files. This misses out on OutputDebugString
calls by anything logging in the DllMain functions of the hook
dlls.

Minor:
- Fix coloring of log entries
- Add ASCII header to easily determine start
- Fix file logging, log _everything_ to a single log file
- Enhance inject's debugger: log further debug events to incrase
visibility on issues, proper exception handling for inject
- Re-iterated code structure of inject
2020-09-02 19:53:06 +00:00
icex2
de894ae5ce util/log: Add log_error which logs errors but does not abort
This is required for tools/applications that want or have to fail
gracefully but still need to highlight the severity in the log.
2020-09-02 19:53:06 +00:00
icex2
1d25abc10b util: Add signal module introducing signal and exception handling
Right now, this prints to the console using the util/log logger
only. Stacktrace on exception still needs to be added.
2020-09-02 19:53:05 +00:00
icex2
beea9e7bb7 util/log: Add TODO pointing out design flaw 2020-09-02 19:53:05 +00:00
icex2
fbb69d4550 Makefile: Fix minor inconsistency 2020-09-02 19:53:05 +00:00
icex2
e0fe9bcf94 Makefile: Fix clang format command 2020-09-02 19:53:05 +00:00
icex2
f9c0733af3 Adapt everything in BT5 to new capnhook API
This includes:
- Renaming of functions (iohook_invoke_next)
- Slight interface changes (com_proxy_wrap, iohook_push_handler)
- De-duplicate stuff from utils (iobuf, hr)
2020-09-02 19:35:15 +00:00
icex2
a016f27652 hook: Update capnhook source files from latest master
https://github.com/decafcode/capnhook
2020-09-02 19:35:15 +00:00
Will Xyen
3a1005f1f8 sdvxio: Add atomics to kfca/bio2 2020-08-16 20:58:12 -07:00
Will Xyen
f1700ca551 sdvxio-bio2: Add better comments to amp command, and sleep in fini 2020-08-15 11:37:03 -07:00
Will Xyen
60b081b01c Merge branch 'sdvxio-bio2' of dev.s-ul.eu:djhackers/bemanitools into sdvxio-bio2 2020-08-14 19:11:57 -07:00
Will Xyen
89989ae49c doc: add documentation for sdvxio-bio2 2020-08-15 02:11:45 +00:00
Will Xyen
ff1b9ff9a2 sdvxio-bio2: Add sdvxio BIO2 along with bio2drv and aciotest updates 2020-08-15 02:11:45 +00:00
Will Xyen
4c0f60fc93 sdvx: Allow setting digital amp level from sdvxio
For SDVX 1-4: passes amp values through as-is

For SDVX5: ignores the amp volume control (as the game uses windows volume controls, which will work without any hooks)
2020-08-15 02:11:45 +00:00
Will Xyen
caba39843f bio2: bio2_bi2a_state -> bi2a_sdvx_state 2020-08-15 02:11:45 +00:00
Will Xyen
f028bdeb20 iidxhook-util: allow setting specified ICCA emulation version 2020-08-15 02:11:44 +00:00
Will Xyen
bfbb7103ef bio2emu: refactor BIO2 emulation 2020-08-15 02:11:44 +00:00
Will Xyen
95e073271f doc: add documentation for sdvxio-bio2 2020-08-14 19:05:44 -07:00
Will Xyen
cdefc2b09e sdvxio-bio2: Add sdvxio BIO2 along with bio2drv and aciotest updates 2020-08-14 18:44:05 -07:00
Will Xyen
9246e7f9e0 sdvx: Allow setting digital amp level from sdvxio
For SDVX 1-4: passes amp values through as-is

For SDVX5: ignores the amp volume control (as the game uses windows volume controls, which will work without any hooks)
2020-08-14 04:38:38 -07:00
icex2
bbb5157460 Version bump 5.33 2020-08-13 13:15:41 +02:00
icex2
e0cfc8c948 Bump to version 5.32 and update changelog 2020-08-13 13:14:54 +02:00
Will Xyen
69ef963451 Merge branch 'master' of dev.s-ul.eu:djhackers/bemanitools 2020-08-12 12:31:14 -07:00
icex2
93cfb591b7 iidxio-ezusb: Update documentation 2020-08-12 18:01:22 +00:00
icex2
3396c09fbf ezusb-iidx: Add macro to enable D01 board emulation
Used for dumping firmware, only. C02 and D01 boards only differ
in the FPGA firmware written to the board on boot up. This doesn't
matter for emulation, but when using a real IO board with
iidxio-ezusb.dll, a different FPGA firmware is required to be
flashed in order to get working turntables, top unit lights etc
2020-08-12 18:01:22 +00:00
icex2
bd8dc18b30 iidxio-ezusb: Support coin mech input 2020-08-11 22:05:46 +02:00
Will Xyen
86517bd001 bio2: bio2_bi2a_state -> bi2a_sdvx_state 2020-08-02 23:16:28 -07:00
Will Xyen
172c83a854 iidxhook-util: allow setting specified ICCA emulation version 2020-08-02 23:03:04 -07:00
Will Xyen
c7137659bc bio2emu: refactor BIO2 emulation 2020-08-02 23:02:13 -07:00
Will Xyen
8e9abf9906 launcher: Set soft_id_code before calling init as some games use it then 2020-07-24 08:47:25 -07:00
Will Xyen
62bb717582 hdxs: Is really an HDXB 1.0.1 apparently
Also update enum hdxs_rgb_light_idx to start from 0 since that's what the function does
2020-07-10 11:06:13 -07:00
Will Xyen
4816fb809d launcher: Use more descriptive error message for ERROR_MOD_NOT_FOUND 2020-07-06 18:03:25 +00:00
Tau
2a2c77f255 Add ddrhook "COM4" passthrough mode 2020-07-01 21:03:47 +02:00
icex2
55513bac41 Update changelog for 5.31 release 2020-07-01 20:33:35 +02:00
Will Xyen
9c37ef71ba ddrio: add some more comments 2020-06-29 11:23:01 -07:00
Will Xyen
a0a1dea397 ddrhook: Add HDXS acio device + emu 2020-06-29 06:52:07 -07:00
Will Xyen
3c26a3f315 ddrio: Add hdxs output functions
Also fixes IDS_DDR_P1_BOTTOM_LIGHT schema being incorrectly mapped (on SD)
2020-06-29 06:51:25 -07:00
Will Xyen
b408cd9687 config: fix number of lights being loaded wrong if config is outdated 2020-06-29 06:49:22 -07:00
Will Xyen
be4df516fd ddrio: Fix p3io and extio lighting output being swapped with one another
the header, mm and smx modules had it right

also fixes p3io responses being the wrong size in 2 cases
2020-06-29 06:47:31 -07:00
Will Xyen
d1080905e5 ddrhook: Adds 64 bit ddr build and related dependencies 2020-06-29 06:43:29 -07:00
Tau
f87a51bbe4 Silence cabinet type spam under DDR A 2020-06-28 22:10:27 -07:00
635e512cccf1256559f0c600d8185deae60a6840
2a4d3e2865 Moved location of ddrio-smx.md to doc/ddrhook/ddrio-smx.md, fixed some formatting, clarified joystick config. 2020-06-28 15:37:29 -04:00
635e512cccf1256559f0c600d8185deae60a6840
6697ff7df1 Included SMX md file with step-by-step instructions and additional info. 2020-06-28 14:47:51 -04:00
Will Xyen
682fe8aa1b crc: forgot an include 2020-06-24 19:25:46 -07:00
Will Xyen
7d533f60cb acioemu: add support for 1.7.0 and encrypted polls 2020-06-25 00:57:59 +00:00
233596621999a3accb78d883a9ab4d1f3460d772
e5331fbc7c jbhook: add adapter hook 2020-06-14 02:22:07 +02:00
10f2d26b708e9205de6ce889920e36b5596f4908
77527e346b popn hid lights 2020-06-08 11:17:22 +02:00
Will Xyen
1d0a96fa20 aciodrv: Make init more consistent by reading until we actually get a 0xAA
(reboots / command interruptions will cause incorrect state on device side)
2020-05-27 08:51:16 -07:00
icex2
63e19aaaf6 Remove src.zip from distribution package
No need to include the source code with the repository being public.
2020-05-11 00:27:11 +02:00
icex2
4c59f16d46 Update gitlab-ci, build project with Dockerfile 2020-05-11 00:27:09 +02:00
icex2
7157fdedb7 Update readme/development doc about docker building 2020-05-11 00:24:21 +02:00
icex2
13d29cb62e Add Dockerfile for building bemanitools with docker 2020-05-11 00:23:53 +02:00
icex2
bf48715466 test: Fix compiler warning 2020-05-11 00:23:29 +02:00
icex2
24b490e36b Bump version to 5.31 2020-04-27 22:00:50 +02:00
icex2
ff2a4b9a2c Changelog 5.30 update 2020-04-27 21:59:33 +02:00
Will Xyen
10bddd4905 d3d9ex: add cursor confining (ported from sdvxhook1) 2020-04-27 12:52:07 -07:00
Will Xyen
ad5fbc1f5b sdvxhook2: Add option to force headphone detection on 2020-04-27 10:19:29 -07:00
Will Xyen
25413bcba8 dinput/asio: drop hook suffix 2020-04-05 02:18:24 -07:00
Will Xyen
937290f93d asiohook: add config 2020-04-05 01:44:42 -07:00
Will Xyen
d04598a570 dinputhook: Adds dinput stub hook for later use
Thanks to felix for the original di8_stub_device.
2020-04-05 01:44:42 -07:00
Will Xyen
bd382e5509 asiohook: Adds asio reghook for later use 2020-04-05 01:44:41 -07:00
Will Xyen
0d3fa54316 launcher: Add before-hook support
Required to hook certain things that happen on module load / avs boot:
 - network adapter hooking for avs
 - envvar setting

Note: the logging facilities are NOT setup yet at this point
so these hooks cannot use avs for logging
2020-04-05 01:42:08 -07:00
6d16ce71d2cb7fb29ef6c9b6fd0f0943018cd3d0
e8943edff6 Add light support for SMX gen 4 pads
The old set lights API doesn't support gen 4 pads. Replace the call to SMX_SetLights with SMX_SetLights2 which adds support for gen 4 pads while maintaining backwards compatibility.
2020-03-22 21:18:38 +01:00
Will Xyen
61f3eb44d2 hooklib: fix warning in adapter.c 2020-02-05 01:26:41 -05:00
icex2
5aa1e27a31 Bump version to 5.30 2020-02-01 11:15:51 +01:00
223 changed files with 9680 additions and 1972 deletions

View File

@@ -1,17 +1,25 @@
image: debian
image: docker:stable
variables:
DOCKER_TLS_CERTDIR: "/certs"
services:
- docker:19.03.8-dind
before_script:
- docker info
stages:
- build
- test
- release
- create-release-package
- releasetag
build:
stage: build
before_script:
- apt-get update && apt-get -qq install clang mingw-w64 git make zip > /dev/null
- apk update && apk add make > /dev/null
script:
- make
- make build-docker
artifacts:
name: "$CI_COMMIT_SHORT_SHA-$CI_JOB_NAME"
paths:
@@ -20,31 +28,17 @@ build:
refs:
- master
test:
allow_failure: true
stage: test
dependencies:
- build
before_script:
- apt-get update && apt-get -qq install make wine unzip > /dev/null
- dpkg --add-architecture i386 && apt-get update && apt-get -qq install wine32 > /dev/null
script:
- ls
- make run-tests
only:
refs:
- master
release:
stage: release
create-release-package:
stage: create-release-package
variables:
GIT_STRATEGY: none
dependencies:
- build
before_script:
- apt-get update && apt-get -qq install zip > /dev/null
- apk update && apk add zip > /dev/null
script:
- mv build/bemanitools.zip ./bemanitools.zip
- mv build/docker/bemanitools.zip ./bemanitools.zip
- rm -r build
- find . -mindepth 1 ! -regex '^./bemanitools.zip' -delete
- unzip bemanitools.zip
- rm bemanitools.zip
@@ -55,12 +49,12 @@ release:
only:
refs:
- master
releasetag:
stage: releasetag
dependencies: []
before_script:
- apt-get update && apt-get -qq install curl > /dev/null
- apk update && apk add curl > /dev/null
script:
- |
curl --silent --show-error \

View File

@@ -1,4 +1,25 @@
# Release history
## 5.33
* iidxhook9: Support for IIDX27
* sdvxio-bio2: Driver for real sdvx5 cabinet IO hardware
* vigem-sdvxio: Tool to allow using sdvxio (kfca or bio2) to emulate an xbox controller
* Various bugfixes and refactoring for inject and launcher
## 5.32
* Various bugfixes
## 5.31
* DDR: Fix p3io and extio lights not working / being swapped when using geninput
* DDR: Add HDXS light support
* DDR: Add 64 bit support
* DDR: Add option to use COM4 as the p3io rs232 port instead of emulating (for use with acrealio etc.)
* Jubeat: Add network adapter hook
* Misc: Fix aciodrv sometimes hanging on boot (eamio-icca and sdvxio-kfca)
## 5.30
* SDVX: sdvxhook2 headphone force and cursor confining config options
* DDR: Add light support for SMX gen 4 pads
## 5.29
* SDVX: Add option for monitor rotation
* SDVX: Add option to allow overriding network adapter IP

32
Dockerfile Normal file
View File

@@ -0,0 +1,32 @@
FROM fedora:31
LABEL description="Build environment for bemanitools"
RUN yum -y install \
git \
make \
zip \
clang \
mingw64-gcc.x86_64 \
mingw32-gcc.x86_64 \
wine.x86_64
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

View File

@@ -11,19 +11,24 @@ BUILDDIR ?= build
# Internal variables
#
depdir := $(BUILDDIR)/dep
objdir := $(BUILDDIR)/obj
bindir := $(BUILDDIR)/bin
builddir_docker := $(BUILDDIR)/docker
toolchain_32 := i686-w64-mingw32-
toolchain_64 := x86_64-w64-mingw32-
docker_container_name := "bemanitools-build"
docker_image_name := "bemanitools:build"
gitrev := $(shell git rev-parse HEAD)
cppflags := -I src -I src/main -I src/test -DGITREV=$(gitrev)
cflags := -O2 -pipe -ffunction-sections -fdata-sections \
-Wall -std=c99
cflags_release := -Werror
ldflags := -Wl,--gc-sections -static-libgcc
depdir := $(BUILDDIR)/dep
objdir := $(BUILDDIR)/obj
bindir := $(BUILDDIR)/bin
toolchain_32 := i686-w64-mingw32-
toolchain_64 := x86_64-w64-mingw32-
gitrev := $(shell git rev-parse HEAD)
cppflags := -I src -I src/main -I src/test -DGITREV=$(gitrev)
cflags := -O2 -pipe -ffunction-sections -fdata-sections \
-Wall -std=c99 -DPSAPI_VERSION=1
cflags_release := -Werror
ldflags := -Wl,--gc-sections -static-libgcc
#
# The first target that GNU Make encounters becomes the default target.
@@ -33,6 +38,7 @@ ldflags := -Wl,--gc-sections -static-libgcc
all: build
.PHONY: \
build-docker \
clean \
code-format \
print-building \
@@ -52,27 +58,36 @@ print-building \
version
print-building:
@echo "Build gitrev "$(gitrev)"..."
$(V)echo "Build gitrev "$(gitrev)"..."
print-release:
@echo "Starting release build..."
$(V)echo "Starting release build..."
clean:
@echo "Cleaning up..."
$(V)echo "Cleaning up..."
$(V)rm -rf $(BUILDDIR)
code-format:
@echo "Applying clang-format..."
# -style=file enables reading .clang-format
@find src/ -iname *.h -o -iname *.c | xargs clang-format -i -style=file
$(V)echo "Applying clang-format..."
$(V)find src/ -name '*.c' -o -name '*.h' | xargs clang-format -i -style=file
run-tests:
@echo "Running tests..."
@./run-tests-wine.sh
$(V)echo "Running tests..."
$(V)./run-tests-wine.sh
# Generate a version file to identify the build
version:
@echo "$(gitrev)" > version
$(V)echo "$(gitrev)" > 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
#
# Pull in module definitions

114
Module.mk
View File

@@ -77,7 +77,10 @@ imps += avs avs-ea3
include src/main/aciodrv/Module.mk
include src/main/acioemu/Module.mk
include src/main/aciotest/Module.mk
include src/main/asio/Module.mk
include src/main/bio2drv/Module.mk
include src/main/bio2emu/Module.mk
include src/main/bio2emu-iidx/Module.mk
include src/main/bsthook/Module.mk
include src/main/bstio/Module.mk
include src/main/camhook/Module.mk
@@ -88,6 +91,7 @@ include src/main/ddrhook/Module.mk
include src/main/ddrio/Module.mk
include src/main/ddrio-smx/Module.mk
include src/main/ddrio-mm/Module.mk
include src/main/dinput/Module.mk
include src/main/eamio/Module.mk
include src/main/eamio-icca/Module.mk
include src/main/eamiotest/Module.mk
@@ -119,12 +123,14 @@ include src/main/iidxhook5/Module.mk
include src/main/iidxhook6/Module.mk
include src/main/iidxhook7/Module.mk
include src/main/iidxhook8/Module.mk
include src/main/iidxhook9/Module.mk
include src/main/iidxio/Module.mk
include src/main/iidxio-ezusb/Module.mk
include src/main/iidxio-ezusb2/Module.mk
include src/main/iidxiotest/Module.mk
include src/main/inject/Module.mk
include src/main/jbio/Module.mk
include src/main/jbiotest/Module.mk
include src/main/jbhook/Module.mk
include src/main/jbhook1/Module.mk
include src/main/launcher/Module.mk
@@ -139,10 +145,13 @@ include src/main/sdvxhook2/Module.mk
include src/main/sdvxhook2-cn/Module.mk
include src/main/sdvxio/Module.mk
include src/main/sdvxio-kfca/Module.mk
include src/main/sdvxio-bio2/Module.mk
include src/main/security/Module.mk
include src/main/unicorntail/Module.mk
include src/main/util/Module.mk
include src/main/vefxio/Module.mk
include src/main/vigem-sdvxio/Module.mk
include src/main/vigemstub/Module.mk
include src/test/cconfig/Module.mk
include src/test/d3d9hook/Module.mk
@@ -169,6 +178,7 @@ $(zipdir)/tools.zip: \
build/bin/indep-32/iidxiotest.exe \
build/bin/indep-32/iidx-ezusb-exit-hook.dll \
build/bin/indep-32/iidx-ezusb2-exit-hook.dll \
build/bin/indep-32/jbiotest.exe \
build/bin/indep-32/pcbidgen.exe \
dist/iidx/ezusb-boot.bat \
dist/iidx/ezusb2-boot.bat \
@@ -181,27 +191,23 @@ $(zipdir)/tools.zip: \
$(V)zip -j $@ $^
$(zipdir)/tools-x64.zip: \
build/bin/indep-64/aciotest.exe \
build/bin/indep-64/eamiotest.exe \
build/bin/indep-64/iidxiotest.exe \
build/bin/indep-64/iidx-ezusb-exit-hook.dll \
build/bin/indep-64/iidx-ezusb2-exit-hook.dll \
build/bin/indep-64/jbiotest.exe \
build/bin/indep-64/mempatch-hook.dll \
| $(zipdir)/
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/src.zip: .git/HEAD $(zipdir)/
$(V)echo ... $@
$(V)git archive -o $@ HEAD
$(zipdir)/iidx-09-to-12.zip: \
build/bin/indep-32/iidxhook1.dll \
build/bin/indep-32/config.exe \
build/bin/indep-32/eamio.dll \
build/bin/indep-32/eamio-icca.dll \
build/bin/indep-32/geninput.dll \
build/bin/indep-32/iidxio.dll \
build/bin/indep-32/iidxio-ezusb.dll \
build/bin/indep-32/iidxio-ezusb2.dll \
build/bin/indep-32/vefxio.dll \
build/bin/indep-32/inject.exe \
dist/iidx/config.bat \
@@ -225,11 +231,8 @@ $(zipdir)/iidx-13.zip: \
build/bin/avs2_0-32/iidxhook2.dll \
build/bin/indep-32/config.exe \
build/bin/indep-32/eamio.dll \
build/bin/indep-32/eamio-icca.dll \
build/bin/indep-32/geninput.dll \
build/bin/indep-32/iidxio.dll \
build/bin/indep-32/iidxio-ezusb.dll \
build/bin/indep-32/iidxio-ezusb2.dll \
build/bin/indep-32/vefxio.dll \
build/bin/indep-32/inject.exe \
dist/iidx/config.bat \
@@ -244,11 +247,8 @@ $(zipdir)/iidx-14-to-17.zip: \
build/bin/avs2_0-32/iidxhook3.dll \
build/bin/indep-32/config.exe \
build/bin/indep-32/eamio.dll \
build/bin/indep-32/eamio-icca.dll \
build/bin/indep-32/geninput.dll \
build/bin/indep-32/iidxio.dll \
build/bin/indep-32/iidxio-ezusb.dll \
build/bin/indep-32/iidxio-ezusb2.dll \
build/bin/indep-32/vefxio.dll \
build/bin/indep-32/inject.exe \
dist/iidx/config.bat \
@@ -270,11 +270,8 @@ $(zipdir)/iidx-18.zip: \
build/bin/avs2_1101-32/launcher.exe \
build/bin/indep-32/config.exe \
build/bin/indep-32/eamio.dll \
build/bin/indep-32/eamio-icca.dll \
build/bin/indep-32/geninput.dll \
build/bin/indep-32/iidxio.dll \
build/bin/indep-32/iidxio-ezusb.dll \
build/bin/indep-32/iidxio-ezusb2.dll \
build/bin/indep-32/vefxio.dll \
dist/iidx/config.bat \
dist/iidx/gamestart-18.bat \
@@ -289,11 +286,8 @@ $(zipdir)/iidx-19.zip: \
build/bin/avs2_1304-32/launcher.exe \
build/bin/indep-32/config.exe \
build/bin/indep-32/eamio.dll \
build/bin/indep-32/eamio-icca.dll \
build/bin/indep-32/geninput.dll \
build/bin/indep-32/iidxio.dll \
build/bin/indep-32/iidxio-ezusb.dll \
build/bin/indep-32/iidxio-ezusb2.dll \
build/bin/indep-32/vefxio.dll \
dist/iidx/config.bat \
dist/iidx/gamestart-19.bat \
@@ -308,11 +302,8 @@ $(zipdir)/iidx-20.zip: \
build/bin/avs2_1508-32/launcher.exe \
build/bin/indep-32/config.exe \
build/bin/indep-32/eamio.dll \
build/bin/indep-32/eamio-icca.dll \
build/bin/indep-32/geninput.dll \
build/bin/indep-32/iidxio.dll \
build/bin/indep-32/iidxio-ezusb.dll \
build/bin/indep-32/iidxio-ezusb2.dll \
build/bin/indep-32/vefxio.dll \
dist/iidx/config.bat \
dist/iidx/gamestart-20.bat \
@@ -327,11 +318,8 @@ $(zipdir)/iidx-21-to-24.zip: \
build/bin/avs2_1601-32/launcher.exe \
build/bin/indep-32/config.exe \
build/bin/indep-32/eamio.dll \
build/bin/indep-32/eamio-icca.dll \
build/bin/indep-32/geninput.dll \
build/bin/indep-32/iidxio.dll \
build/bin/indep-32/iidxio-ezusb.dll \
build/bin/indep-32/iidxio-ezusb2.dll \
build/bin/indep-32/vefxio.dll \
dist/iidx/config.bat \
dist/iidx/gamestart-21.bat \
@@ -352,11 +340,8 @@ $(zipdir)/iidx-25-to-26.zip: \
build/bin/avs2_1700-64/launcher.exe \
build/bin/indep-64/config.exe \
build/bin/indep-64/eamio.dll \
build/bin/indep-64/eamio-icca.dll \
build/bin/indep-64/geninput.dll \
build/bin/indep-64/iidxio.dll \
build/bin/indep-64/iidxio-ezusb.dll \
build/bin/indep-64/iidxio-ezusb2.dll \
build/bin/indep-64/vefxio.dll \
dist/iidx/config.bat \
dist/iidx/gamestart-25.bat \
@@ -368,6 +353,38 @@ $(zipdir)/iidx-25-to-26.zip: \
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/iidx-27.zip: \
build/bin/avs2_1700-64/iidxhook9.dll \
build/bin/avs2_1700-64/launcher.exe \
build/bin/indep-64/config.exe \
build/bin/indep-64/eamio.dll \
build/bin/indep-64/geninput.dll \
build/bin/indep-64/iidxio.dll \
build/bin/indep-64/vefxio.dll \
dist/iidx/config.bat \
dist/iidx/gamestart-27.bat \
dist/iidx/iidxhook-27.conf \
dist/iidx/vefx.txt \
| $(zipdir)/
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/iidx-hwio-x86.zip: \
build/bin/indep-32/eamio-icca.dll \
build/bin/indep-32/iidxio-ezusb.dll \
build/bin/indep-32/iidxio-ezusb2.dll \
| $(zipdir)/
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/iidx-hwio-x64.zip: \
build/bin/indep-64/eamio-icca.dll \
build/bin/indep-64/iidxio-ezusb.dll \
build/bin/indep-64/iidxio-ezusb2.dll \
| $(zipdir)/
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/jb-01.zip: \
build/bin/avs2_803-32/jbhook1.dll \
build/bin/indep-32/inject.exe \
@@ -415,7 +432,6 @@ $(zipdir)/sdvx-01-to-04.zip: \
build/bin/indep-32/eamio.dll \
build/bin/indep-32/geninput.dll \
build/bin/indep-32/sdvxio.dll \
build/bin/indep-32/sdvxio-kfca.dll \
dist/sdvx/config.bat \
dist/sdvx/gamestart.bat \
| $(zipdir)/
@@ -429,7 +445,6 @@ $(zipdir)/sdvx-05.zip: \
build/bin/indep-64/eamio.dll \
build/bin/indep-64/geninput.dll \
build/bin/indep-64/sdvxio.dll \
build/bin/indep-64/sdvxio-kfca.dll \
dist/sdvx5/config.bat \
dist/sdvx5/gamestart.bat \
dist/sdvx5/sdvxhook2.conf \
@@ -451,6 +466,22 @@ $(zipdir)/sdvx-05-cn.zip: \
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/sdvx-hwio-x86.zip: \
build/bin/indep-32/sdvxio-kfca.dll \
build/bin/indep-32/sdvxio-bio2.dll \
build/bin/indep-32/vigem-sdvxio.exe \
| $(zipdir)/
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/sdvx-hwio-x64.zip: \
build/bin/indep-64/sdvxio-kfca.dll \
build/bin/indep-64/sdvxio-bio2.dll \
build/bin/indep-64/vigem-sdvxio.exe \
| $(zipdir)/
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/ddr-12-to-16.zip: \
build/bin/avs2_1508-32/launcher.exe \
build/bin/avs2_1508-32/ddrhook.dll \
@@ -471,6 +502,22 @@ $(zipdir)/ddr-12-to-16.zip: \
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/ddr-16-x64.zip: \
build/bin/avs2_1603-64/launcher.exe \
build/bin/avs2_1603-64/ddrhook.dll \
build/bin/avs2_1603-64/unicorntail.dll \
build/bin/indep-64/config.exe \
build/bin/indep-64/ddrio.dll \
build/bin/indep-64/ddrio-mm.dll \
build/bin/indep-64/ddrio-smx.dll \
build/bin/indep-64/eamio.dll \
build/bin/indep-64/geninput.dll \
dist/ddr/config.bat \
dist/ddr/gamestart-16.bat \
| $(zipdir)/
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/bst.zip: \
build/bin/avs2_1603-64/bsthook.dll \
build/bin/avs2_1603-64/launcher.exe \
@@ -523,6 +570,7 @@ $(BUILDDIR)/tests.zip: \
$(BUILDDIR)/bemanitools.zip: \
$(zipdir)/bst.zip \
$(zipdir)/ddr-12-to-16.zip \
$(zipdir)/ddr-16-x64.zip \
$(zipdir)/doc.zip \
$(zipdir)/iidx-09-to-12.zip \
$(zipdir)/iidx-13.zip \
@@ -532,13 +580,17 @@ $(BUILDDIR)/bemanitools.zip: \
$(zipdir)/iidx-20.zip \
$(zipdir)/iidx-21-to-24.zip \
$(zipdir)/iidx-25-to-26.zip \
$(zipdir)/iidx-27.zip \
$(zipdir)/iidx-hwio-x86.zip \
$(zipdir)/iidx-hwio-x64.zip \
$(zipdir)/jb-01.zip \
$(zipdir)/jb-05-to-07.zip \
$(zipdir)/jb-08.zip \
$(zipdir)/src.zip \
$(zipdir)/sdvx-01-to-04.zip \
$(zipdir)/sdvx-05.zip \
$(zipdir)/sdvx-05-cn.zip \
$(zipdir)/sdvx-hwio-x86.zip \
$(zipdir)/sdvx-hwio-x64.zip \
$(zipdir)/tools.zip \
$(zipdir)/tools-x64.zip \
CHANGELOG.md \

View File

@@ -1,7 +1,8 @@
# Bemanitools 5
[![pipeline status](https://dev.s-ul.eu/djhackers/bemanitools/badges/master/pipeline.svg)](https://dev.s-ul.eu/djhackers/bemanitools/commits/master)
Version: 5.29</br>
Version: 5.33
[Release history](CHANGELOG.md)
A collection of tools to run [various Bemani arcade games](#list-of-supported-games).
@@ -40,6 +41,7 @@ authentic gameplay experience, and easier support for a broader range of release
* Beatmania IIDX 24 SINOBUZ (iidx-21-to-24.zip) using [iidxhook7](doc/iidxhook/iidxhook7.md)
* Beatmania IIDX 25 CANNON BALLERS (iidx-25-to-26.zip) using [iidxhook8](doc/iidxhook/iidxhook8.md)
* Beatmania IIDX 26 Rootage (iidx-25-to-26.zip) using [iidxhook8](doc/iidxhook/iidxhook8.md)
* Beatmania IIDX 27 Heroic Verse (iidx-27.zip) using [iidxhook9](doc/iidxhook/iidxhook9.md)
* jubeat
* jubeat (experimental/buggy) (jb-01.zip) using [jbhook1](doc/jbhook1/jbhook1.md)
* jubeat saucer (fulfill) (jb-05-to-07.zip) using jbhook
@@ -81,6 +83,9 @@ should cover most if not all of the games so far
Please refer to the [dedicated documentation](CONTRIBUTING.md).
# Development
## Building
See the [development document](doc/development).
## Architecture
A dedicate [architecture document](doc/architecture.md) outlines the architecture of Bemanitools and points out the most
important aspects you should know before you get started with development.
@@ -88,10 +93,6 @@ important aspects you should know before you get started with development.
## API
Please refer to the [API documentation](doc/api.md).
## Source Code
The source code is included with this distribution package (src.zip). Please refer to the
[development document](doc/development.md) for further details.
# License
Source code license is the Unlicense; you are permitted to do with this as thou wilt. For details, please refer to the
[LICENSE file](LICENSE) included with the source code.

16
dist/iidx/gamestart-27.bat vendored Normal file
View File

@@ -0,0 +1,16 @@
@echo off
cd /d %~dp0
if not exist dev mkdir dev
if not exist dev\e mkdir dev\e
if not exist dev\g mkdir dev\g
if not exist dev\nvram mkdir dev\nvram
if not exist dev\raw mkdir dev\raw
if not exist dev\raw\log mkdir dev\raw\log
if not exist dev\raw\fscache mkdir dev\raw\fscache
for /R prop\defaults %%D in (*.*) do (
if not exist dev\nvram\%%~nxD copy /y prop\defaults\%%~nxD dev\nvram
)
launcher -H 134217728 -B iidxhook9.dll bm2dx.dll --config iidxhook-27.conf %*

63
dist/iidx/iidxhook-27.conf vendored Normal file
View File

@@ -0,0 +1,63 @@
# Disable card reader emulation and enable usage of real card reader hardware on COM0 (for games supporting slotted readers)
io.disable_card_reader_emu=false
# Disable BIO2 emulation and enable usage of real BIO2 hardware
io.disable_bio2_emu=false
# Disables the poll limiter, warning very high CPU usage may arise
io.disable_poll_limiter=false
# Lightning cab mode (requires additional IO emulation)
io.lightning_mode=false
# Disable camera connection
io.disable_cams=false
# Disables the built in file hooks, requiring manual file creation
io.disable_file_hooks=false
# Disables the camera emulation
cam.disable_emu=false
# Override camera device ID detection (copy from device manager, do not escape)
cam.device_id1=
# Override camera device ID detection (copy from device manager, do not escape)
cam.device_id2=
# Run the game in a framed window (requires windowed option)
gfx.framed=true
# Run the game windowed
gfx.windowed=false
# Confine mouse coursor to window
gfx.confined=false
# Windowed width, -1 for default size
gfx.window_width=-1
# Windowed height, -1 for default size
gfx.window_height=-1
# Forced refresh rate, -1 to not force any (try 59 or 60 if monitor check fails to lock on high refresh rate monitors)
gfx.forced_refresh_rate=-1
# D3D9ex device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1
# Orientation to force monitor into, -1 to use default, 0, 1, 2, 3 to do 0, 90, 180, 270 degrees
gfx.force_orientation=-1
# IP of adapter to force override with
adapter.override_ip=
# Force ASIO audio mode/device (if applicable / TDJ default)
asio.force_asio=false
# Force WASAPI audio mode (if applicable / LDJ default)
asio.force_wasapi=true
# The ASIO device name to use
asio.device_name=XONAR SOUND CARD(64)

View File

@@ -7,12 +7,21 @@ io.disable_bio2_emu=false
# Disables the poll limiter, warning very high CPU usage may arise
io.disable_poll_limiter=false
# Forces game to think headphones are attached
io.force_headphones=false
# Disables the built in file hooks, requiring manual file creation (/dev/raw/j.dest)
io.disable_file_hooks=false
# Run the game in a framed window (requires windowed option)
gfx.framed=true
# Run the game windowed
gfx.windowed=false
# Confine mouse coursor to window
gfx.confined=false
# Windowed width, -1 for default size
gfx.window_width=1080

14
doc/ddrhook/ddrio-smx.md Normal file
View File

@@ -0,0 +1,14 @@
# Using SMX pads with BemaniTools (DDR Ace and higher)
If you are looking to use StepManiaX pads with DDR, these are supported **natively** for Gen 1 through Gen 5.(And theoretically beyond!) Steps and info below
## Step-by-Step
1. Ensure that you have the latest `SMX.dll` copied to your contents folder. The easiest way to get this is to download and install the latest SMX Config program on [StepManiaX.com](https://data.stepmaniax.com/docs/SMXConfigInstaller-2020-04-03-01.exe). `SMX.dll`'s default install location is `C:\Program Files (x86)\SMXConfig`
2. After bemanitools has been copied to your contents folder, rename the regular `ddrio.dll` to something like `ddrio-orig.dll`.
3. Rename `ddrio-smx.dll` to `ddrio.dll`.
4. Use the config tool to set up the usual stuff.(cards, network, etc.) Be sure to map menu, test, service, and start buttons to your keyboard or other controllers. You **cannot** map SMX panels as joystick inputs.
5. Start the game. If everything works properly, the game will boot and your panels will light up when stepped on during gameplay and song selection.
## Important Things
* Pad panel inputs (UDLR on P1 and P2) are mapped automatically. If you've purchased a single pad from StepManiaX, this jumper is installed and will set your pad to P2 by default. If you want to change to P1, you'll need to open up your pads and remove this jumper in the [MCU box](https://data.stepmaniax.com/docs/Stage%20-%20Gen%205%20Manual%20Rev1.pdf).
* Panel colors set in the SMX config tool are not used. Colors are set internally by Bemanitools.
* If you get a warning about setlights2 when starting the game, your `SMX.dll` is likely out of date. Make sure you've downloaded the latest version of the StepManiaX config tool from stepmaniax.com and have copied the `SMX.dll` to your contents folder.

View File

@@ -58,6 +58,18 @@ command:
make release
```
## Building with docker
You can also build bemanitools using docker which avoids having to setup a full development
environment if you are just interested in building binaries for the latest changes. Naturally, this
requires you to have the docker daemon installed. Then, run the following command from the root
folder of the project:
```bash
make build-docker
```
Once completed successfully, the build output is located in the `build/docker` sub-folder.
## Creating releases
For developers to create official releases with major and minor versioning:
1. Ensure that all everything you want to have for this release is merged into master.

View File

@@ -23,6 +23,7 @@ games:
* [iidxhook6](iidxhook6.md): Tricoro
* [iidxhook7](iidxhook7.md): SPADA, PENDUAL, copula, SINOBUZ
* [iidxhook8](iidxhook8.md): CANNON BALLERS, Rootage
* [iidxhook8](iidxhook9.md): Heroic Verse
When building kactools, independent packages are created for each set of games
which are ready to be dropped on top of vanilla AC data dumps. We recommend

View File

@@ -2,6 +2,7 @@
The following games are compatible with this version of iidxhook:
* CANNON BALLERS
* Rootage
The games must be bootstrapped using [launcher](../launcher.md).

179
doc/iidxhook/iidxhook9.md Normal file
View File

@@ -0,0 +1,179 @@
# Game list
The following games are compatible with this version of iidxhook:
* Heroic Verse
The games must be bootstrapped using [launcher](../launcher.md).
# Data setup and running the game
## Supported versions of Windows
This version requires at least Win 7 x64 and will not run, like the
former versions, on Win XP x86!
## Dependencies
Make sure to have the following dependencies installed:
* DirectX 9
* Visual C++ 2010 Redistributable Package (x64)
## Data setup
We assume that you are using a clean/vanilla data dump. Ensure your ("concents")
folder with your unpacked data looks like this:
- data
- modules
- prop
* Copy/Move all files from the *modules* directory to the root folder, so they
are located next to the *data* and *prop* folders.
* Copy all files from *prop/defaults* to the *prop* folder.
* Setup proper paths for *dev/nvram* and *dev/raw* in *prop/avs-config.xml* by
replacing the *<fs>*-block in that file with the following block:
```
<fs>
<root>
<device __type="str">.</device>
</root>
<mounttable>
<vfs name="boot" fstype="fs" src="dev/raw" dst="/dev/raw" opt="vf=1,posix=1"/>
<vfs name="boot" fstype="fs" src="dev/nvram" dst="/dev/nvram" opt="vf=0,posix=1"/>
</mounttable>
<nr_mountpoint __type="u16">256</nr_mountpoint>
<nr_filedesc __type="u16">256</nr_filedesc>
</fs>
```
* Unpack the package containing iidxhook9 into the root folder so iidxhook9.dll
and all other files are located in the same folder as *data*, *prop*,
*bm2dx.dll*, etc.
* Run the gamestart-XX.bat file as admin. Where XX matches the version you
want to run.
* Note: if you know what you're doing and would like to keep all the dlls in the
*modules* folder then you extract iidxhook9 into that directory, move
gamestart-XX.bat up, and edit the paths.
# Configuring iidxhook
The hook library can be configured via cmd arguments or a configuration file.
The latter is generated (*iidxhook-XX.conf* in the same directory) on the first
start of the game using the gamestart-XX.bat file (again, XX matches your target
game version). It contains default values for all available parameters and
comments explaining each parameter. Please follow the comments when configuring
your setup.
Add the argument *-h* when running gamestart-XX.bat
(e.g. *gamestart-XX.bat -h*) to print help/usage information with a list of
all available parameters. Every parameter can be either set as command line
argument or using a configuration file.
To set a parameter from the command line, just add it as an argument after
the bat file like this
```
gamestart-09.bat -p gfx.windowed=true -p gfx.framed=true
```
The syntax for the "key=value" is the same as in the config file. Make sure
to have a pre-ceeding "-p" for every parameter added.
However, if a parameter is specifed in the configuration file and as a command
line argument, the command line argument overrides the config file's value.
# Eamuse network setup
If you want to run the games online, you need a valid PCBID and the service URL.
Open *prop/ea3-config.xml* and set the values of the *ea3/id/pcbid* and
*ea3/network/services* nodes accordingly.
Run the game with the gamestart-XX.bat file and enable network on the operator
menu. When enabled, the game seems to hang and expects you to power
cycle the machine (i.e. quit the game and restart it).
# Real hardware support
### BIO2 hardware
Set the *io.disable_bio2_emu* configuration value to *1* to disable BIO2
emulation to run the game using real BIO2 hardware.
### Ezusb and other
Use the specific iidxio API implementations, e.g. iidxio-ezusb2.dll to use
the IO2 EZUSB board, to run the game on real hardware. Thanks to a common
abstraction layer, you can also use custom IO boards or whatever Konami hardware
is going to be available in the future. Obviously, someone has to write a
driver, first.
## Slotted/Wave pass card readers
Replace the default *eamio.dll* with the *eamio-icca.dll* and have either your
slotted (IIDX, DDR Supernova or GF/DM type) or new wave pass card readers
conencted and and assigned to *COM1*.
### ICCA device settings (device manager)
* Port: COM1
* BAUD rate: 57600
* Data bits: 8
* Parity: None
* Stop bits: 1
* Flow control: None
If you encounter issues after the game opened the device, e.g. application
stuck, try a USB <-> COM dongle instead of using one of the COM ports of the
mainboard.
# Troubleshooting and FAQ
## The game does not run "well" (frame drops, drifting offsync etc)
This can be related to various issues:
* Make sure to run the game as (true) Administrator especially on Windows 7 and
newer. This will also get rid of various other errors (see below) that are
related to permission issues.
* Run the game's process with a higher priority:
```
start "" /relatime "gamestart.bat"
```
* Enforce v-sync enabled in your GPU settings.
* Ensure that you have a constant refresh rate around the 60 hz (59.9xx or 60.0xx)
that is not jumping around. Use the timebase feature of one of the newer games to
check that or enable iidxhook's timebase and check the log output for the
determined value. Run this a few times and check if the results differ.
## "NETWORK WARNING" instead of "NETWORK OK"
This can be caused by:
* Invalid PCBID
* Firewall blocking connections
* Invalid eamuse url or port specified
* Game is not run using the Administrator account
Make sure to check these things first
## My songs are offsync
From IIDX 20 (or Lincle very final revision) onwards, the game comes with
a built-in auto timebase option ("monitor check" on startup) which
dynamically, detects the refresh rate of your current setup. Thus, BT5's
timebase option is not included from this hook version onwards, anymore.
Ensure that refresh rate displayed is very stable, e.g. 60.00x hz, and the
game should be able to provide you with a smooth and sync game experience.
## My game runs too fast
iidxhook can limit the frame rate for you (refer to help/config file)
## My game crashes when I try fullscreen
Use dxwnd and set settings like "Acquire admin caps" and "Fullscreen only"
## Background videos aren't working. When starting a song, windows is playing the error sound and a message box appears
You are missing a codec to decode and play the videos. There are different
methods available to get background videos working. Probably, the easiest
solution: grab the CLVSD.ax file and go to Start -> Run -> regsvr32 clvsd.ax
Make sure to run cmd.exe as Administrator, otherwise you will get errors caused
by invalid permissions.
## I installed the CLVSD.ax codec but the game crashes or displays a message box that tells me to disable my debugger
If songs keep crashing upon start and you get an error message that says
```
DirectShow Texture3D Sample
Could not create source filter to graph! hr=0x80040266
```
despite having the codec (CLVSD.ax) installed, remove the debug flag (*-D*)
from gamestart or use a CLVSD.ax codec which has the debugger checks removed.

View File

@@ -1,4 +1,4 @@
This library drives a "legacy" ezusb IO board, also known as C02 IO, and
This library drives a "legacy" ezusb IO board, also known as C02/D01 IO, and
implements the iidxio API of BT5. Thus, it allows you to use this IO board with
*any* version of IIDX that is supported by BT5.
@@ -24,5 +24,7 @@ the status LEDs on the side of the board should show a blinking pattern.
dump to the FPGA.
* There is a script called ezusb-boot.bat which combines the two steps above
and can be integrated into the startup process of a dedicated setup.
* If you are using a D01 IO board, use the `fpga-d01.bin` file instead of the
`fpga.bin` file.
* If you ignore these steps, you will either run into errors or parts of the
IO board won't work (e.g. lights).

View File

@@ -0,0 +1,18 @@
This library talks to a BIO2 BI2A node and implements the sdvxio API of BT5.
Thus, it allows you to use a BIO2 SDVX device board with *any* version of SDVX that is supported by BT5.
# Setup
* Make sure that your BIO2 is flashed with a SDVX firmware (if you can boot SDVX5 with it, it's already the right firmware)
* The firmware persists between boots, so as long as it's flashed to the correct firmware, you no longer need to do this step
* Rename sdvxio-kfca.dll to sdvxio.dll.
* Ensure that your gamestart.bat actually injects the appropriate sdvxhook dll
for example:
```
launcher -K sdvxhook.dll soundvoltex.dll ...*
```
or that the application otherwise uses sdvxio.dll
* sdvxio-bio2 implements BIO2 device autodetection
* if this fails please make a bug report, and set the port manually in the config
* You can change the port and baudrate by editing the sdvxio-bio2.conf that should be created by default
* Please connect any additional acio devices to their own port (ex: SDVX5 expects an ICCA by itself on COM2)

View File

@@ -0,0 +1,24 @@
This application allows you to use any sdvxio backend, e.g. `sdvxio-kfca.dll`, to be available as a XBOX 360 game controller on windows.
Thus, it allows you to use a real cab with *any* game that supports xinput.
# Setup
* Install [ViGEmBus](https://github.com/ViGEm/ViGEmBus/releases)
* Place the following in the same folder as vigem-sdvxio:
* Get a copy of [ViGEmClient.dll](https://bin.jvnv.net/file/ZgMJK/ViGEmClient.zip) (or from bemanitools-supplements)
* Rename your corresponding `sdvxio-XXX.dll`, e.g. `sdvxio-kfca.dll`, to `sdvxio.dll`.
* Run `vigem-sdvxio.exe` so that the config file gets created
* Edit `vigem-sdvxio.conf` so that the config file gets created as needed
# Usage
* Run `vigem-sdvxio.exe`
* To quit the program, hit the TEST + SERVICE button at the same time
# Mapping
* BT ABCD are mapped to ABXY
* FX LR are mapped to LB/RB
* VOL LR are mapped to L thumbstick X/Y (either in absolute or relative mode depending on the config)
# Additional Notes For Cabinets (Running on embedded Windows 7):
* Make sure that you follow the instructions exactly from the release page ([Prerequisites for Windows 7](https://github.com/ViGEm/ViGEmBus/wiki/Prerequisites-for-Windows-7))
* If you get an error while trying to install KB3033929, re-enable windows update
* Make sure to ewfmgr C: -commit and reboot after installing the drivers (this only needs to be done once)

3
doc/tools/jbiotest.md Normal file
View File

@@ -0,0 +1,3 @@
Testing tool for development of jbio libraries used for emulating the main io
hardware on bemanitools for jubeat. Just place jbiotest.exe and your
custom jbio.dll in the same folder and run jbiotest.exe.

View File

@@ -61,14 +61,24 @@ SMX_EXTERN_C SMX_API void SMX_GetInfo(int pad, struct SMXInfo *info);
// Get a mask of the currently pressed panels.
SMX_EXTERN_C SMX_API uint16_t SMX_GetInputState(int pad);
// Update the lights. Both pads are always updated together. lightsData is a
// list of 8-bit RGB colors, one for each LED. Each panel has lights in the
// following order:
// (deprecated) Equivalent to SMX_SetLights2(lightsData, 864).
SMX_API void SMX_SetLights(const char lightData[864]);
// Update the lights. Both pads are always updated together. lightData is a list of 8-bit RGB
// colors, one for each LED.
//
// 0123
// 4567
// 89AB
// CDEF
// lightDataSize is the number of bytes in lightsData. This should be 1350 (2 pads * 9 panels *
// 25 lights * 3 RGB colors). For backwards-compatibility, this can also be 864.
//
// Each panel has lights in the following order:
//
// 00 01 02 03
// 16 17 18
// 04 05 06 07
// 19 20 21
// 08 09 10 11
// 22 23 24
// 12 13 14 15
//
// Panels are in the following order:
//
@@ -76,17 +86,17 @@ SMX_EXTERN_C SMX_API uint16_t SMX_GetInputState(int pad);
// 345 CDE
// 678 F01
//
// With 18 panels, 16 LEDs per panel and 3 bytes per LED, each light update has
// 864 bytes of data.
// With 18 panels, 25 LEDs per panel and 3 bytes per LED, each light update has 1350 bytes of data.
//
// Lights will update at up to 30 FPS. If lights data is sent more quickly, a
// best effort will be made to send the most recent lights data available, but
// the panels won't update more quickly.
// Lights will update at up to 30 FPS. If lights data is sent more quickly, a best effort will be
// made to send the most recent lights data available, but the panels won't update more quickly.
//
// The panels will return to automatic lighting if no lights are received for a
// while, so applications controlling lights should send light updates
// continually, even if the lights aren't changing.
SMX_EXTERN_C SMX_API void SMX_SetLights(const char lightsData[864]);
// The panels will return to automatic lighting if no lights are received for a while, so applications
// controlling lights should send light updates continually, even if the lights aren't changing.
//
// For backwards compatibility, if lightDataSize is 864, the old 4x4-only order is used,
// which simply omits lights 16-24.
SMX_API void SMX_SetLights2(const char *lightData, int lightDataSize);
// By default, the panels light automatically when stepped on. If a lights
// command is sent by the application, this stops happening to allow the

519
src/imports/ViGEm/Client.h Normal file
View File

@@ -0,0 +1,519 @@
/*
MIT License
Copyright (c) 2017-2019 Nefarius Software Solutions e.U. and Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef ViGEmClient_h__
#define ViGEmClient_h__
#ifdef __cplusplus
extern "C" {
#endif
#include "ViGEm/Common.h"
#ifdef VIGEM_DYNAMIC
#ifdef VIGEM_EXPORTS
#define VIGEM_API __declspec(dllexport)
#else
#define VIGEM_API __declspec(dllimport)
#endif
#else
#define VIGEM_API
#endif
/**
* \typedef enum _VIGEM_ERRORS
*
* \brief Defines an alias representing the ViGEm errors.
*/
typedef enum _VIGEM_ERRORS {
VIGEM_ERROR_NONE = 0x20000000,
VIGEM_ERROR_BUS_NOT_FOUND = 0xE0000001,
VIGEM_ERROR_NO_FREE_SLOT = 0xE0000002,
VIGEM_ERROR_INVALID_TARGET = 0xE0000003,
VIGEM_ERROR_REMOVAL_FAILED = 0xE0000004,
VIGEM_ERROR_ALREADY_CONNECTED = 0xE0000005,
VIGEM_ERROR_TARGET_UNINITIALIZED = 0xE0000006,
VIGEM_ERROR_TARGET_NOT_PLUGGED_IN = 0xE0000007,
VIGEM_ERROR_BUS_VERSION_MISMATCH = 0xE0000008,
VIGEM_ERROR_BUS_ACCESS_FAILED = 0xE0000009,
VIGEM_ERROR_CALLBACK_ALREADY_REGISTERED = 0xE0000010,
VIGEM_ERROR_CALLBACK_NOT_FOUND = 0xE0000011,
VIGEM_ERROR_BUS_ALREADY_CONNECTED = 0xE0000012,
VIGEM_ERROR_BUS_INVALID_HANDLE = 0xE0000013,
VIGEM_ERROR_XUSB_USERINDEX_OUT_OF_RANGE = 0xE0000014,
VIGEM_ERROR_INVALID_PARAMETER = 0xE0000015
} VIGEM_ERROR;
/**
* \def VIGEM_SUCCESS(_val_) (_val_ == VIGEM_ERROR_NONE);
*
* \brief A macro that defines success.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param _val_ The VIGEM_ERROR value.
*/
#define VIGEM_SUCCESS(_val_) (_val_ == VIGEM_ERROR_NONE)
/**
* \typedef struct _VIGEM_CLIENT_T *PVIGEM_CLIENT
*
* \brief Defines an alias representing a driver connection object.
*/
typedef struct _VIGEM_CLIENT_T *PVIGEM_CLIENT;
/**
* \typedef struct _VIGEM_TARGET_T *PVIGEM_TARGET
*
* \brief Defines an alias representing a target device object.
*/
typedef struct _VIGEM_TARGET_T *PVIGEM_TARGET;
typedef _Function_class_(EVT_VIGEM_TARGET_ADD_RESULT) VOID CALLBACK
EVT_VIGEM_TARGET_ADD_RESULT(
PVIGEM_CLIENT Client, PVIGEM_TARGET Target, VIGEM_ERROR Result);
typedef EVT_VIGEM_TARGET_ADD_RESULT *PFN_VIGEM_TARGET_ADD_RESULT;
typedef _Function_class_(EVT_VIGEM_X360_NOTIFICATION) VOID CALLBACK
EVT_VIGEM_X360_NOTIFICATION(
PVIGEM_CLIENT Client,
PVIGEM_TARGET Target,
UCHAR LargeMotor,
UCHAR SmallMotor,
UCHAR LedNumber,
LPVOID UserData);
typedef EVT_VIGEM_X360_NOTIFICATION *PFN_VIGEM_X360_NOTIFICATION;
typedef _Function_class_(EVT_VIGEM_DS4_NOTIFICATION) VOID CALLBACK
EVT_VIGEM_DS4_NOTIFICATION(
PVIGEM_CLIENT Client,
PVIGEM_TARGET Target,
UCHAR LargeMotor,
UCHAR SmallMotor,
DS4_LIGHTBAR_COLOR LightbarColor,
LPVOID UserData);
typedef EVT_VIGEM_DS4_NOTIFICATION *PFN_VIGEM_DS4_NOTIFICATION;
/**
* \fn PVIGEM_CLIENT vigem_alloc(void);
*
* \brief Allocates an object representing a driver connection.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \return A new driver connection object.
*/
VIGEM_API PVIGEM_CLIENT vigem_alloc(void);
/**
* \fn void vigem_free(PVIGEM_CLIENT vigem);
*
* \brief Frees up memory used by the driver connection object.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param vigem The driver connection object.
*/
VIGEM_API void vigem_free(PVIGEM_CLIENT vigem);
/**
* \fn VIGEM_ERROR vigem_connect(PVIGEM_CLIENT vigem);
*
* \brief Initializes the driver object and establishes a connection to the
* emulation bus driver. Returns an error if no compatible bus device has been
* found.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param vigem The driver connection object.
*
* \return A VIGEM_ERROR.
*/
VIGEM_API VIGEM_ERROR vigem_connect(PVIGEM_CLIENT vigem);
/**
* \fn void vigem_disconnect(PVIGEM_CLIENT vigem);
*
* \brief Disconnects from the bus device and resets the driver object state.
* The driver object may be reused again after calling this function. When
* called, all targets which may still be connected will be destroyed
* automatically. Be aware, that allocated target objects won't be automatically
* freed, this has to be taken care of by the caller.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param vigem The driver connection object.
*/
VIGEM_API void vigem_disconnect(PVIGEM_CLIENT vigem);
/**
* \fn PVIGEM_TARGET vigem_target_x360_alloc(void);
*
* \brief Allocates an object representing an Xbox 360 Controller device.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \return A PVIGEM_TARGET representing an Xbox 360 Controller device.
*/
VIGEM_API PVIGEM_TARGET vigem_target_x360_alloc(void);
/**
* \fn PVIGEM_TARGET vigem_target_ds4_alloc(void);
*
* \brief Allocates an object representing a DualShock 4 Controller device.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \return A PVIGEM_TARGET representing a DualShock 4 Controller device.
*/
VIGEM_API PVIGEM_TARGET vigem_target_ds4_alloc(void);
/**
* \fn void vigem_target_free(PVIGEM_TARGET target);
*
* \brief Frees up memory used by the target device object. This does not
* automatically remove the associated device from the bus, if present. If the
* target device doesn't get removed before this call, the device becomes
* orphaned until the owning process is terminated.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param target The target device object.
*/
VIGEM_API void vigem_target_free(PVIGEM_TARGET target);
/**
* \fn VIGEM_ERROR vigem_target_add(PVIGEM_CLIENT vigem, PVIGEM_TARGET target);
*
* \brief Adds a provided target device to the bus driver, which is equal to a
* device plug-in event of a physical hardware device. This function blocks
* until the target device is in full operational mode.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param vigem The driver connection object.
* \param target The target device object.
*
* \return A VIGEM_ERROR.
*/
VIGEM_API VIGEM_ERROR
vigem_target_add(PVIGEM_CLIENT vigem, PVIGEM_TARGET target);
/**
* \fn VIGEM_ERROR vigem_target_add_async(PVIGEM_CLIENT vigem, PVIGEM_TARGET
* target, PVIGEM_TARGET_ADD_RESULT result);
*
* \brief Adds a provided target device to the bus driver, which is equal to a
* device plug-in event of a physical hardware device. This function immediately
* returns. An optional callback may be registered which gets called on error or
* if the target device has become fully operational.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param vigem The driver connection object.
* \param target The target device object.
* \param result An optional function getting called when the target device
* becomes available.
*
* \return A VIGEM_ERROR.
*/
VIGEM_API VIGEM_ERROR vigem_target_add_async(
PVIGEM_CLIENT vigem,
PVIGEM_TARGET target,
PFN_VIGEM_TARGET_ADD_RESULT result);
/**
* \fn VIGEM_ERROR vigem_target_remove(PVIGEM_CLIENT vigem, PVIGEM_TARGET
* target);
*
* \brief Removes a provided target device from the bus driver, which is equal
* to a device unplug event of a physical hardware device. The target device
* object may be reused after this function is called. If this function is never
* called on target device objects, they will be removed from the bus when the
* owning process terminates.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param vigem The driver connection object.
* \param target The target device object.
*
* \return A VIGEM_ERROR.
*/
VIGEM_API VIGEM_ERROR
vigem_target_remove(PVIGEM_CLIENT vigem, PVIGEM_TARGET target);
/**
* \fn VIGEM_ERROR vigem_target_x360_register_notification(PVIGEM_CLIENT vigem,
* PVIGEM_TARGET target, PVIGEM_X360_NOTIFICATION notification);
*
* \brief Registers a function which gets called, when LED index or vibration
* state changes occur on the provided target device. This function fails if the
* provided target device isn't fully operational or in an erroneous state.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param vigem The driver connection object.
* \param target The target device object.
* \param notification The notification callback.
* \param userData The user data passed to the notification callback.
*
* \return A VIGEM_ERROR.
*/
VIGEM_API VIGEM_ERROR vigem_target_x360_register_notification(
PVIGEM_CLIENT vigem,
PVIGEM_TARGET target,
PFN_VIGEM_X360_NOTIFICATION notification,
LPVOID userData);
/**
* \fn VIGEM_ERROR vigem_target_ds4_register_notification(PVIGEM_CLIENT vigem,
* PVIGEM_TARGET target, PVIGEM_DS4_NOTIFICATION notification);
*
* \brief Registers a function which gets called, when LightBar or vibration
* state changes occur on the provided target device. This function fails if the
* provided target device isn't fully operational or in an erroneous state.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param vigem The driver connection object.
* \param target The target device object.
* \param notification The notification callback.
* \param userData The user data passed to the notification callback.
*
* \return A VIGEM_ERROR.
*/
VIGEM_API VIGEM_ERROR vigem_target_ds4_register_notification(
PVIGEM_CLIENT vigem,
PVIGEM_TARGET target,
PFN_VIGEM_DS4_NOTIFICATION notification,
LPVOID userData);
/**
* \fn void vigem_target_x360_unregister_notification(PVIGEM_TARGET target);
*
* \brief Removes a previously registered callback function from the provided
* target object.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param target The target device object.
*/
VIGEM_API void vigem_target_x360_unregister_notification(PVIGEM_TARGET target);
/**
* \fn void vigem_target_ds4_unregister_notification(PVIGEM_TARGET target);
*
* \brief Removes a previously registered callback function from the provided
* target object.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param target The target device object.
*/
VIGEM_API void vigem_target_ds4_unregister_notification(PVIGEM_TARGET target);
/**
* \fn void vigem_target_set_vid(PVIGEM_TARGET target, USHORT vid);
*
* \brief Overrides the default Vendor ID value with the provided one.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param target The target device object.
* \param vid The Vendor ID to set.
*/
VIGEM_API void vigem_target_set_vid(PVIGEM_TARGET target, USHORT vid);
/**
* \fn void vigem_target_set_pid(PVIGEM_TARGET target, USHORT pid);
*
* \brief Overrides the default Product ID value with the provided one.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param target The target device object.
* \param pid The Product ID to set.
*/
VIGEM_API void vigem_target_set_pid(PVIGEM_TARGET target, USHORT pid);
/**
* \fn USHORT vigem_target_get_vid(PVIGEM_TARGET target);
*
* \brief Returns the Vendor ID of the provided target device object.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param target The target device object.
*
* \return The Vendor ID.
*/
VIGEM_API USHORT vigem_target_get_vid(PVIGEM_TARGET target);
/**
* \fn USHORT vigem_target_get_pid(PVIGEM_TARGET target);
*
* \brief Returns the Product ID of the provided target device object.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param target The target device object.
*
* \return The Product ID.
*/
VIGEM_API USHORT vigem_target_get_pid(PVIGEM_TARGET target);
/**
* \fn VIGEM_ERROR vigem_target_x360_update(PVIGEM_CLIENT vigem, PVIGEM_TARGET
* target, XUSB_REPORT report);
*
* \brief Sends a state report to the provided target device.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param vigem The driver connection object.
* \param target The target device object.
* \param report The report to send to the target device.
*
* \return A VIGEM_ERROR.
*/
VIGEM_API VIGEM_ERROR vigem_target_x360_update(
PVIGEM_CLIENT vigem, PVIGEM_TARGET target, XUSB_REPORT report);
/**
* \fn VIGEM_ERROR vigem_target_ds4_update(PVIGEM_CLIENT vigem, PVIGEM_TARGET
* target, DS4_REPORT report);
*
* \brief Sends a state report to the provided target device.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param vigem The driver connection object.
* \param target The target device object.
* \param report The report to send to the target device.
*
* \return A VIGEM_ERROR.
*/
VIGEM_API VIGEM_ERROR vigem_target_ds4_update(
PVIGEM_CLIENT vigem, PVIGEM_TARGET target, DS4_REPORT report);
/**
* \fn ULONG vigem_target_get_index(PVIGEM_TARGET target);
*
* \brief Returns the internal index (serial number) the bus driver assigned
* to the provided target device object. Note that this value is specific to the
* inner workings of the bus driver, it does not reflect related values like
* player index or device arrival order experienced by other APIs. It may be
* used to identify the target device object for its lifetime. This value
* becomes invalid once the target device is removed from the bus and may change
* on the next addition of the device.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param target The target device object.
*
* \return The internally used index of the target device.
*/
VIGEM_API ULONG vigem_target_get_index(PVIGEM_TARGET target);
/**
* \fn VIGEM_TARGET_TYPE vigem_target_get_type(PVIGEM_TARGET target);
*
* \brief Returns the type of the provided target device object.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 28.08.2017
*
* \param target The target device object.
*
* \return A VIGEM_TARGET_TYPE.
*/
VIGEM_API VIGEM_TARGET_TYPE vigem_target_get_type(PVIGEM_TARGET target);
/**
* \fn BOOL vigem_target_is_attached(PVIGEM_TARGET target);
*
* \brief Returns TRUE if the provided target device object is currently
* attached to the bus, FALSE otherwise.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 30.08.2017
*
* \param target The target device object.
*
* \return TRUE if device is attached to the bus, FALSE otherwise.
*/
VIGEM_API BOOL vigem_target_is_attached(PVIGEM_TARGET target);
/**
* \fn VIGEM_API VIGEM_ERROR vigem_target_x360_get_user_index(PVIGEM_CLIENT
* vigem, PVIGEM_TARGET target, PULONG index);
*
* \brief Returns the user index of the emulated Xenon device. This value
* correspondents to the (zero-based) index number representing the player
* number via LED present on a physical controller and is compatible to the
* dwUserIndex propery of the XInput* APIs.
*
* \author Benjamin "Nefarius" H<>glinger
* \date 10.05.2018
*
* \param vigem The driver connection object.
* \param target The target device object.
* \param index The (zero-based) user index of the Xenon device.
*
* \return A VIGEM_ERROR.
*/
VIGEM_API VIGEM_ERROR vigem_target_x360_get_user_index(
PVIGEM_CLIENT vigem, PVIGEM_TARGET target, PULONG index);
#ifdef __cplusplus
}
#endif
#endif // ViGEmClient_h__

191
src/imports/ViGEm/Common.h Normal file
View File

@@ -0,0 +1,191 @@
/*
MIT License
Copyright (c) 2017-2019 Nefarius Software Solutions e.U. and Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
//
// Represents the desired target type for the emulated device.
//
typedef enum _VIGEM_TARGET_TYPE {
//
// Microsoft Xbox 360 Controller (wired)
//
Xbox360Wired = 0,
//
// Sony DualShock 4 (wired)
//
DualShock4Wired = 2 // NOTE: 1 skipped on purpose to maintain compatibility
} VIGEM_TARGET_TYPE,
*PVIGEM_TARGET_TYPE;
//
// Possible XUSB report buttons.
//
typedef enum _XUSB_BUTTON {
XUSB_GAMEPAD_DPAD_UP = 0x0001,
XUSB_GAMEPAD_DPAD_DOWN = 0x0002,
XUSB_GAMEPAD_DPAD_LEFT = 0x0004,
XUSB_GAMEPAD_DPAD_RIGHT = 0x0008,
XUSB_GAMEPAD_START = 0x0010,
XUSB_GAMEPAD_BACK = 0x0020,
XUSB_GAMEPAD_LEFT_THUMB = 0x0040,
XUSB_GAMEPAD_RIGHT_THUMB = 0x0080,
XUSB_GAMEPAD_LEFT_SHOULDER = 0x0100,
XUSB_GAMEPAD_RIGHT_SHOULDER = 0x0200,
XUSB_GAMEPAD_GUIDE = 0x0400,
XUSB_GAMEPAD_A = 0x1000,
XUSB_GAMEPAD_B = 0x2000,
XUSB_GAMEPAD_X = 0x4000,
XUSB_GAMEPAD_Y = 0x8000
} XUSB_BUTTON,
*PXUSB_BUTTON;
//
// Represents an XINPUT_GAMEPAD-compatible report structure.
//
typedef struct _XUSB_REPORT {
USHORT wButtons;
BYTE bLeftTrigger;
BYTE bRightTrigger;
SHORT sThumbLX;
SHORT sThumbLY;
SHORT sThumbRX;
SHORT sThumbRY;
} XUSB_REPORT, *PXUSB_REPORT;
//
// Initializes a _XUSB_REPORT structure.
//
VOID FORCEINLINE XUSB_REPORT_INIT(_Out_ PXUSB_REPORT Report)
{
RtlZeroMemory(Report, sizeof(XUSB_REPORT));
}
//
// The color value (RGB) of a DualShock 4 Lightbar
//
typedef struct _DS4_LIGHTBAR_COLOR {
//
// Red part of the Lightbar (0-255).
//
UCHAR Red;
//
// Green part of the Lightbar (0-255).
//
UCHAR Green;
//
// Blue part of the Lightbar (0-255).
//
UCHAR Blue;
} DS4_LIGHTBAR_COLOR, *PDS4_LIGHTBAR_COLOR;
//
// DualShock 4 digital buttons
//
typedef enum _DS4_BUTTONS {
DS4_BUTTON_THUMB_RIGHT = 1 << 15,
DS4_BUTTON_THUMB_LEFT = 1 << 14,
DS4_BUTTON_OPTIONS = 1 << 13,
DS4_BUTTON_SHARE = 1 << 12,
DS4_BUTTON_TRIGGER_RIGHT = 1 << 11,
DS4_BUTTON_TRIGGER_LEFT = 1 << 10,
DS4_BUTTON_SHOULDER_RIGHT = 1 << 9,
DS4_BUTTON_SHOULDER_LEFT = 1 << 8,
DS4_BUTTON_TRIANGLE = 1 << 7,
DS4_BUTTON_CIRCLE = 1 << 6,
DS4_BUTTON_CROSS = 1 << 5,
DS4_BUTTON_SQUARE = 1 << 4
} DS4_BUTTONS,
*PDS4_BUTTONS;
//
// DualShock 4 special buttons
//
typedef enum _DS4_SPECIAL_BUTTONS {
DS4_SPECIAL_BUTTON_PS = 1 << 0,
DS4_SPECIAL_BUTTON_TOUCHPAD = 1 << 1
} DS4_SPECIAL_BUTTONS,
*PDS4_SPECIAL_BUTTONS;
//
// DualShock 4 directional pad (HAT) values
//
typedef enum _DS4_DPAD_DIRECTIONS {
DS4_BUTTON_DPAD_NONE = 0x8,
DS4_BUTTON_DPAD_NORTHWEST = 0x7,
DS4_BUTTON_DPAD_WEST = 0x6,
DS4_BUTTON_DPAD_SOUTHWEST = 0x5,
DS4_BUTTON_DPAD_SOUTH = 0x4,
DS4_BUTTON_DPAD_SOUTHEAST = 0x3,
DS4_BUTTON_DPAD_EAST = 0x2,
DS4_BUTTON_DPAD_NORTHEAST = 0x1,
DS4_BUTTON_DPAD_NORTH = 0x0
} DS4_DPAD_DIRECTIONS,
*PDS4_DPAD_DIRECTIONS;
//
// DualShock 4 HID Input report
//
typedef struct _DS4_REPORT {
BYTE bThumbLX;
BYTE bThumbLY;
BYTE bThumbRX;
BYTE bThumbRY;
USHORT wButtons;
BYTE bSpecial;
BYTE bTriggerL;
BYTE bTriggerR;
} DS4_REPORT, *PDS4_REPORT;
//
// Sets the current state of the D-PAD on a DualShock 4 report.
//
VOID FORCEINLINE
DS4_SET_DPAD(_Out_ PDS4_REPORT Report, _In_ DS4_DPAD_DIRECTIONS Dpad)
{
Report->wButtons &= ~0xF;
Report->wButtons |= (USHORT) Dpad;
}
VOID FORCEINLINE DS4_REPORT_INIT(_Out_ PDS4_REPORT Report)
{
RtlZeroMemory(Report, sizeof(DS4_REPORT));
Report->bThumbLX = 0x80;
Report->bThumbLY = 0x80;
Report->bThumbRX = 0x80;
Report->bThumbRY = 0x80;
DS4_SET_DPAD(Report, DS4_BUTTON_DPAD_NONE);
}

68
src/imports/ViGEm/Util.h Normal file
View File

@@ -0,0 +1,68 @@
#pragma once
#include "ViGEm/Common.h"
#include <limits.h>
VOID FORCEINLINE
XUSB_TO_DS4_REPORT(_Out_ PXUSB_REPORT Input, _Out_ PDS4_REPORT Output)
{
if (Input->wButtons & XUSB_GAMEPAD_BACK)
Output->wButtons |= DS4_BUTTON_SHARE;
if (Input->wButtons & XUSB_GAMEPAD_START)
Output->wButtons |= DS4_BUTTON_OPTIONS;
if (Input->wButtons & XUSB_GAMEPAD_LEFT_THUMB)
Output->wButtons |= DS4_BUTTON_THUMB_LEFT;
if (Input->wButtons & XUSB_GAMEPAD_RIGHT_THUMB)
Output->wButtons |= DS4_BUTTON_THUMB_RIGHT;
if (Input->wButtons & XUSB_GAMEPAD_LEFT_SHOULDER)
Output->wButtons |= DS4_BUTTON_SHOULDER_LEFT;
if (Input->wButtons & XUSB_GAMEPAD_RIGHT_SHOULDER)
Output->wButtons |= DS4_BUTTON_SHOULDER_RIGHT;
if (Input->wButtons & XUSB_GAMEPAD_GUIDE)
Output->bSpecial |= DS4_SPECIAL_BUTTON_PS;
if (Input->wButtons & XUSB_GAMEPAD_A)
Output->wButtons |= DS4_BUTTON_CROSS;
if (Input->wButtons & XUSB_GAMEPAD_B)
Output->wButtons |= DS4_BUTTON_CIRCLE;
if (Input->wButtons & XUSB_GAMEPAD_X)
Output->wButtons |= DS4_BUTTON_SQUARE;
if (Input->wButtons & XUSB_GAMEPAD_Y)
Output->wButtons |= DS4_BUTTON_TRIANGLE;
Output->bTriggerL = Input->bLeftTrigger;
Output->bTriggerR = Input->bRightTrigger;
if (Input->bLeftTrigger > 0)
Output->wButtons |= DS4_BUTTON_TRIGGER_LEFT;
if (Input->bRightTrigger > 0)
Output->wButtons |= DS4_BUTTON_TRIGGER_RIGHT;
if (Input->wButtons & XUSB_GAMEPAD_DPAD_UP)
DS4_SET_DPAD(Output, DS4_BUTTON_DPAD_NORTH);
if (Input->wButtons & XUSB_GAMEPAD_DPAD_RIGHT)
DS4_SET_DPAD(Output, DS4_BUTTON_DPAD_EAST);
if (Input->wButtons & XUSB_GAMEPAD_DPAD_DOWN)
DS4_SET_DPAD(Output, DS4_BUTTON_DPAD_SOUTH);
if (Input->wButtons & XUSB_GAMEPAD_DPAD_LEFT)
DS4_SET_DPAD(Output, DS4_BUTTON_DPAD_WEST);
if (Input->wButtons & XUSB_GAMEPAD_DPAD_UP &&
Input->wButtons & XUSB_GAMEPAD_DPAD_RIGHT)
DS4_SET_DPAD(Output, DS4_BUTTON_DPAD_NORTHEAST);
if (Input->wButtons & XUSB_GAMEPAD_DPAD_RIGHT &&
Input->wButtons & XUSB_GAMEPAD_DPAD_DOWN)
DS4_SET_DPAD(Output, DS4_BUTTON_DPAD_SOUTHEAST);
if (Input->wButtons & XUSB_GAMEPAD_DPAD_DOWN &&
Input->wButtons & XUSB_GAMEPAD_DPAD_LEFT)
DS4_SET_DPAD(Output, DS4_BUTTON_DPAD_SOUTHWEST);
if (Input->wButtons & XUSB_GAMEPAD_DPAD_LEFT &&
Input->wButtons & XUSB_GAMEPAD_DPAD_UP)
DS4_SET_DPAD(Output, DS4_BUTTON_DPAD_NORTHWEST);
Output->bThumbLX = ((Input->sThumbLX + ((USHRT_MAX / 2) + 1)) / 257);
Output->bThumbLY = (-(Input->sThumbLY + ((USHRT_MAX / 2) - 1)) / 257);
Output->bThumbLY = (Output->bThumbLY == 0) ? 0xFF : Output->bThumbLY;
Output->bThumbRX = ((Input->sThumbRX + ((USHRT_MAX / 2) + 1)) / 257);
Output->bThumbRY = (-(Input->sThumbRY + ((USHRT_MAX / 2) + 1)) / 257);
Output->bThumbRY = (Output->bThumbRY == 0) ? 0xFF : Output->bThumbRY;
}

View File

@@ -0,0 +1,399 @@
/*
MIT License
Copyright (c) 2016-2019 Nefarius Software Solutions e.U. and Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
//
// GUID identifying the bus device. Used by client library to detect and
// communicate.
//
// IMPORTANT: make sure to change this value if you fork it or introduce
// breaking changes!
//
// {96E42B22-F5E9-42F8-B043-ED0F932F014F}
DEFINE_GUID(
GUID_DEVINTERFACE_BUSENUM_VIGEM,
0x96E42B22,
0xF5E9,
0x42F8,
0xB0,
0x43,
0xED,
0x0F,
0x93,
0x2F,
0x01,
0x4F);
#pragma once
#include "ViGEm/Common.h"
//
// Common version for user-mode library and driver compatibility
//
// On initialization, the user-mode library has this number embedded
// and sends it to the bus on its enumeration. The bus compares this
// number to the one it was compiled with. If they match, the bus
// access is permitted and success reported. If they mismatch, an
// error is reported and the user-mode library skips this instance.
//
#define VIGEM_COMMON_VERSION 0x0001
#define FILE_DEVICE_BUSENUM FILE_DEVICE_BUS_EXTENDER
#define BUSENUM_IOCTL(_index_) \
CTL_CODE(FILE_DEVICE_BUSENUM, _index_, METHOD_BUFFERED, FILE_READ_DATA)
#define BUSENUM_W_IOCTL(_index_) \
CTL_CODE(FILE_DEVICE_BUSENUM, _index_, METHOD_BUFFERED, FILE_WRITE_DATA)
#define BUSENUM_R_IOCTL(_index_) \
CTL_CODE(FILE_DEVICE_BUSENUM, _index_, METHOD_BUFFERED, FILE_READ_DATA)
#define BUSENUM_RW_IOCTL(_index_) \
CTL_CODE( \
FILE_DEVICE_BUSENUM, \
_index_, \
METHOD_BUFFERED, \
FILE_WRITE_DATA | FILE_READ_DATA)
#define IOCTL_VIGEM_BASE 0x801
//
// IO control codes
//
#define IOCTL_VIGEM_PLUGIN_TARGET BUSENUM_W_IOCTL(IOCTL_VIGEM_BASE + 0x000)
#define IOCTL_VIGEM_UNPLUG_TARGET BUSENUM_W_IOCTL(IOCTL_VIGEM_BASE + 0x001)
#define IOCTL_VIGEM_CHECK_VERSION BUSENUM_W_IOCTL(IOCTL_VIGEM_BASE + 0x002)
#define IOCTL_XUSB_REQUEST_NOTIFICATION \
BUSENUM_RW_IOCTL(IOCTL_VIGEM_BASE + 0x200)
#define IOCTL_XUSB_SUBMIT_REPORT BUSENUM_W_IOCTL(IOCTL_VIGEM_BASE + 0x201)
#define IOCTL_DS4_SUBMIT_REPORT BUSENUM_W_IOCTL(IOCTL_VIGEM_BASE + 0x202)
#define IOCTL_DS4_REQUEST_NOTIFICATION BUSENUM_W_IOCTL(IOCTL_VIGEM_BASE + 0x203)
//#define IOCTL_XGIP_SUBMIT_REPORT BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE +
//0x204) #define IOCTL_XGIP_SUBMIT_INTERRUPT BUSENUM_W_IOCTL
//(IOCTL_VIGEM_BASE + 0x205)
#define IOCTL_XUSB_GET_USER_INDEX BUSENUM_RW_IOCTL(IOCTL_VIGEM_BASE + 0x206)
//
// Data structure used in PlugIn and UnPlug ioctls
//
#pragma region Plugin
//
// Data structure used in IOCTL_VIGEM_PLUGIN_TARGET requests.
//
typedef struct _VIGEM_PLUGIN_TARGET {
//
// sizeof (struct _BUSENUM_HARDWARE)
//
IN ULONG Size;
//
// Serial number of target device.
//
IN ULONG SerialNo;
//
// Type of the target device to emulate.
//
VIGEM_TARGET_TYPE TargetType;
//
// If set, the vendor ID the emulated device is reporting
//
USHORT VendorId;
//
// If set, the product ID the emulated device is reporting
//
USHORT ProductId;
} VIGEM_PLUGIN_TARGET, *PVIGEM_PLUGIN_TARGET;
//
// Initializes a VIGEM_PLUGIN_TARGET structure.
//
VOID FORCEINLINE VIGEM_PLUGIN_TARGET_INIT(
_Out_ PVIGEM_PLUGIN_TARGET PlugIn,
_In_ ULONG SerialNo,
_In_ VIGEM_TARGET_TYPE TargetType)
{
RtlZeroMemory(PlugIn, sizeof(VIGEM_PLUGIN_TARGET));
PlugIn->Size = sizeof(VIGEM_PLUGIN_TARGET);
PlugIn->SerialNo = SerialNo;
PlugIn->TargetType = TargetType;
}
#pragma endregion
#pragma region Unplug
//
// Data structure used in IOCTL_VIGEM_UNPLUG_TARGET requests.
//
typedef struct _VIGEM_UNPLUG_TARGET {
//
// sizeof (struct _REMOVE_HARDWARE)
//
IN ULONG Size;
//
// Serial number of target device.
//
ULONG SerialNo;
} VIGEM_UNPLUG_TARGET, *PVIGEM_UNPLUG_TARGET;
//
// Initializes a VIGEM_UNPLUG_TARGET structure.
//
VOID FORCEINLINE
VIGEM_UNPLUG_TARGET_INIT(_Out_ PVIGEM_UNPLUG_TARGET UnPlug, _In_ ULONG SerialNo)
{
RtlZeroMemory(UnPlug, sizeof(VIGEM_UNPLUG_TARGET));
UnPlug->Size = sizeof(VIGEM_UNPLUG_TARGET);
UnPlug->SerialNo = SerialNo;
}
#pragma endregion
#pragma region Check version
typedef struct _VIGEM_CHECK_VERSION {
IN ULONG Size;
IN ULONG Version;
} VIGEM_CHECK_VERSION, *PVIGEM_CHECK_VERSION;
VOID FORCEINLINE VIGEM_CHECK_VERSION_INIT(
_Out_ PVIGEM_CHECK_VERSION CheckVersion, _In_ ULONG Version)
{
RtlZeroMemory(CheckVersion, sizeof(VIGEM_CHECK_VERSION));
CheckVersion->Size = sizeof(VIGEM_CHECK_VERSION);
CheckVersion->Version = Version;
}
#pragma endregion
#pragma region XUSB(aka Xbox 360 device) section
//
// Data structure used in IOCTL_XUSB_REQUEST_NOTIFICATION requests.
//
typedef struct _XUSB_REQUEST_NOTIFICATION {
//
// sizeof(struct _XUSB_REQUEST_NOTIFICATION)
//
ULONG Size;
//
// Serial number of target device.
//
ULONG SerialNo;
//
// Vibration intensity value of the large motor (0-255).
//
UCHAR LargeMotor;
//
// Vibration intensity value of the small motor (0-255).
//
UCHAR SmallMotor;
//
// Index number of the slot/LED that XUSB.sys has assigned.
//
UCHAR LedNumber;
} XUSB_REQUEST_NOTIFICATION, *PXUSB_REQUEST_NOTIFICATION;
//
// Initializes a XUSB_REQUEST_NOTIFICATION structure.
//
VOID FORCEINLINE XUSB_REQUEST_NOTIFICATION_INIT(
_Out_ PXUSB_REQUEST_NOTIFICATION Request, _In_ ULONG SerialNo)
{
RtlZeroMemory(Request, sizeof(XUSB_REQUEST_NOTIFICATION));
Request->Size = sizeof(XUSB_REQUEST_NOTIFICATION);
Request->SerialNo = SerialNo;
}
//
// Data structure used in IOCTL_XUSB_SUBMIT_REPORT requests.
//
typedef struct _XUSB_SUBMIT_REPORT {
//
// sizeof(struct _XUSB_SUBMIT_REPORT)
//
ULONG Size;
//
// Serial number of target device.
//
ULONG SerialNo;
//
// Report to submit to the target device.
//
XUSB_REPORT Report;
} XUSB_SUBMIT_REPORT, *PXUSB_SUBMIT_REPORT;
//
// Initializes an XUSB report.
//
VOID FORCEINLINE
XUSB_SUBMIT_REPORT_INIT(_Out_ PXUSB_SUBMIT_REPORT Report, _In_ ULONG SerialNo)
{
RtlZeroMemory(Report, sizeof(XUSB_SUBMIT_REPORT));
Report->Size = sizeof(XUSB_SUBMIT_REPORT);
Report->SerialNo = SerialNo;
}
typedef struct _XUSB_GET_USER_INDEX {
//
// sizeof(struct _XUSB_GET_USER_INDEX)
//
ULONG Size;
//
// Serial number of target device.
//
ULONG SerialNo;
//
// User index of target device.
//
OUT ULONG UserIndex;
} XUSB_GET_USER_INDEX, *PXUSB_GET_USER_INDEX;
//
// Initializes XUSB_GET_USER_INDEX structure.
//
VOID FORCEINLINE XUSB_GET_USER_INDEX_INIT(
_Out_ PXUSB_GET_USER_INDEX GetRequest, _In_ ULONG SerialNo)
{
RtlZeroMemory(GetRequest, sizeof(XUSB_GET_USER_INDEX));
GetRequest->Size = sizeof(XUSB_GET_USER_INDEX);
GetRequest->SerialNo = SerialNo;
}
#pragma endregion
#pragma region DualShock 4 section
typedef struct _DS4_OUTPUT_REPORT {
//
// Vibration intensity value of the small motor (0-255).
//
UCHAR SmallMotor;
//
// Vibration intensity value of the large motor (0-255).
//
UCHAR LargeMotor;
//
// Color values of the Lightbar.
//
DS4_LIGHTBAR_COLOR LightbarColor;
} DS4_OUTPUT_REPORT, *PDS4_OUTPUT_REPORT;
//
// Data structure used in IOCTL_DS4_REQUEST_NOTIFICATION requests.
//
typedef struct _DS4_REQUEST_NOTIFICATION {
//
// sizeof(struct _XUSB_REQUEST_NOTIFICATION)
//
ULONG Size;
//
// Serial number of target device.
//
ULONG SerialNo;
//
// The HID output report
//
DS4_OUTPUT_REPORT Report;
} DS4_REQUEST_NOTIFICATION, *PDS4_REQUEST_NOTIFICATION;
//
// Initializes a DS4_REQUEST_NOTIFICATION structure.
//
VOID FORCEINLINE DS4_REQUEST_NOTIFICATION_INIT(
_Out_ PDS4_REQUEST_NOTIFICATION Request, _In_ ULONG SerialNo)
{
RtlZeroMemory(Request, sizeof(DS4_REQUEST_NOTIFICATION));
Request->Size = sizeof(DS4_REQUEST_NOTIFICATION);
Request->SerialNo = SerialNo;
}
//
// DualShock 4 request data
//
typedef struct _DS4_SUBMIT_REPORT {
//
// sizeof(struct _DS4_SUBMIT_REPORT)
//
ULONG Size;
//
// Serial number of target device.
//
ULONG SerialNo;
//
// HID Input report
//
DS4_REPORT Report;
} DS4_SUBMIT_REPORT, *PDS4_SUBMIT_REPORT;
//
// Initializes a DualShock 4 report.
//
VOID FORCEINLINE
DS4_SUBMIT_REPORT_INIT(_Out_ PDS4_SUBMIT_REPORT Report, _In_ ULONG SerialNo)
{
RtlZeroMemory(Report, sizeof(DS4_SUBMIT_REPORT));
Report->Size = sizeof(DS4_SUBMIT_REPORT);
Report->SerialNo = SerialNo;
DS4_REPORT_INIT(&Report->Report);
}
#pragma endregion

View File

@@ -230,4 +230,6 @@ int avs_fs_addfs(void *filesys_struct);
int avs_fs_mount(
const char *mountpoint, const char *fsroot, const char *fstype, void *data);
bool avs_is_active();
#endif

View File

@@ -7,6 +7,7 @@ EXPORTS
SMX_GetInfo
SMX_GetInputState
SMX_SetLights
SMX_SetLights2
SMX_ReenableAutoLights
SMX_GetConfig
SMX_SetConfig

View File

@@ -0,0 +1,27 @@
LIBRARY ViGEmClient
EXPORTS
vigem_alloc
vigem_connect
vigem_disconnect
vigem_free
vigem_target_add
vigem_target_add_async
vigem_target_ds4_alloc
vigem_target_ds4_register_notification
vigem_target_ds4_unregister_notification
vigem_target_ds4_update
vigem_target_free
vigem_target_get_index
vigem_target_get_pid
vigem_target_get_type
vigem_target_get_vid
vigem_target_is_attached
vigem_target_remove
vigem_target_set_pid
vigem_target_set_vid
vigem_target_x360_alloc
vigem_target_x360_get_user_index
vigem_target_x360_register_notification
vigem_target_x360_unregister_notification
vigem_target_x360_update

View File

@@ -23,6 +23,7 @@ EXPORTS
std_setenv @213 NONAME
avs_boot @298 NONAME
avs_shutdown @299 NONAME
avs_is_active @302 NONAME
log_body_fatal @379 NONAME
log_body_warning @380 NONAME
log_body_info @381 NONAME

View File

@@ -0,0 +1,18 @@
LIBRARY SMX
EXPORTS
SMX_Start
SMX_Stop
SMX_SetLogCallback
SMX_GetInfo
SMX_GetInputState
SMX_SetLights
SMX_SetLights2
SMX_ReenableAutoLights
SMX_GetConfig
SMX_SetConfig
SMX_FactoryReset
SMX_ForceRecalibration
SMX_SetTestMode
SMX_GetTestData
SMX_Version

View File

@@ -0,0 +1,27 @@
LIBRARY ViGEmClient
EXPORTS
vigem_alloc
vigem_connect
vigem_disconnect
vigem_free
vigem_target_add
vigem_target_add_async
vigem_target_ds4_alloc
vigem_target_ds4_register_notification
vigem_target_ds4_unregister_notification
vigem_target_ds4_update
vigem_target_free
vigem_target_get_index
vigem_target_get_pid
vigem_target_get_type
vigem_target_get_vid
vigem_target_is_attached
vigem_target_remove
vigem_target_set_pid
vigem_target_set_vid
vigem_target_x360_alloc
vigem_target_x360_get_user_index
vigem_target_x360_register_notification
vigem_target_x360_unregister_notification
vigem_target_x360_update

View File

@@ -5,6 +5,7 @@
#include <stdint.h>
#include <stdlib.h>
#include "acio/hdxs.h"
#include "acio/icca.h"
#include "acio/kfca.h"
@@ -35,6 +36,7 @@ enum ac_io_node_type {
AC_IO_NODE_TYPE_LED_SPIKE = 0x05010000,
AC_IO_NODE_TYPE_KFCA = 0x09060000,
AC_IO_NODE_TYPE_BI2A = 0x0d060000,
AC_IO_NODE_TYPE_RVOL = 0x09060001,
};
#pragma pack(push, 1)
@@ -71,6 +73,8 @@ struct ac_io_message {
struct ac_io_kfca_poll_in kfca_poll_in;
struct ac_io_kfca_poll_out kfca_poll_out;
struct ac_io_hdxs_output hdxs_output;
};
} cmd;

48
src/main/acio/hdxs.h Normal file
View File

@@ -0,0 +1,48 @@
#ifndef ACIO_HDXS_H
#define ACIO_HDXS_H
#include <stdint.h>
enum ac_io_hdxs_cmd {
AC_IO_HDXS_CMD_SET_OUTPUTS = 0x0112,
};
#pragma pack(push, 1)
struct ac_io_hdxs_light {
uint8_t analog : 7; // rgb component
uint8_t bit : 1; // buttons
};
struct ac_io_hdxs_output {
uint8_t empty;
struct ac_io_hdxs_light lights[12];
};
enum ac_io_hdxs_front_panel_lights {
AC_IO_HDXS_OUT_P1_START = 0,
AC_IO_HDXS_OUT_P1_UP_DOWN = 1,
AC_IO_HDXS_OUT_P1_LEFT_RIGHT = 2,
AC_IO_HDXS_OUT_P2_START = 3,
AC_IO_HDXS_OUT_P2_UP_DOWN = 4,
AC_IO_HDXS_OUT_P2_LEFT_RIGHT = 5,
};
enum ac_io_hdxs_grb_layout {
AC_IO_HDXS_GREEN = 0,
AC_IO_HDXS_RED = 1,
AC_IO_HDXS_BLUE = 2,
};
enum ac_io_hdxs_speaker_lights {
AC_IO_HDXS_OUT_P1_SPEAKER_F = 0,
AC_IO_HDXS_OUT_P2_SPEAKER_F = 1,
AC_IO_HDXS_OUT_P1_SPEAKER_W = 2,
AC_IO_HDXS_OUT_P2_SPEAKER_W = 3,
};
_Static_assert(
sizeof(struct ac_io_hdxs_output) == 13,
"ac_io_hdxs_output is the wrong size");
#pragma pack(pop)
#endif

View File

@@ -12,6 +12,8 @@ enum ac_io_icca_cmd {
AC_IO_ICCA_CMD_SET_SLOT_STATE = 0x0135,
AC_IO_ICCA_CMD_BEGIN_KEYPAD = 0x013A,
AC_IO_ICCA_CMD_POLL_FELICA = 0x0161,
AC_IO_ICCA_CMD_KEY_EXCHANGE = 0x0160,
AC_IO_ICCA_CMD_POLL_ENCRYPTED = 0x0164,
};
enum ac_io_icca_slot_state {

View File

@@ -1,6 +1,8 @@
#ifndef AC_IO_KFCA_H
#define AC_IO_KFCA_H
#include <stdint.h>
#define AC_IO_CMD_KFCA_POLL 0x0113
#define AC_IO_CMD_KFCA_WATCHDOG 0x0120
#define AC_IO_CMD_KFCA_AMP_CONTROL 0x0128

View File

@@ -19,6 +19,7 @@ static char aviodrv_device_node_products[16][4];
static bool aciodrv_device_init(void)
{
uint8_t init_seq[1] = {AC_IO_SOF};
uint8_t read_buff[1] = {0x00};
/* init/reset the device by sending 0xAA until 0xAA is returned */
int read = 0;
@@ -27,17 +28,20 @@ static bool aciodrv_device_init(void)
return false;
}
read = aciodrv_port_read(init_seq, sizeof(init_seq));
} while (read == 0);
read = aciodrv_port_read(read_buff, sizeof(read_buff));
} while ((read <= 0) || (read_buff[0] != init_seq[0]));
if (read > 0) {
log_warning("Obtained SOF, clearing out buffer now");
/* empty buffer by reading all data */
while (read > 0) {
read = aciodrv_port_read(init_seq, sizeof(init_seq));
}
log_warning("Cleared buffer, init done");
return read == 0;
} else {
log_warning("Read failure when trying to clear device state");
return false;
}
}
@@ -162,6 +166,7 @@ static int aciodrv_device_receive(uint8_t *buffer, int size)
#ifdef AC_IO_MSG_LOG
aciodrv_device_log_buffer("Recv (1)", recv_buf, recv_size);
log_warning("Expected %d got %d", recv_buf[4], recv_size - 6);
#endif
/* recv_size - 1: omit checksum for checksum calc */
@@ -314,15 +319,24 @@ bool aciodrv_device_get_node_product_ident(uint8_t node_id, char product[4])
bool aciodrv_send_and_recv(struct ac_io_message *msg, int resp_size)
{
msg->cmd.seq_no = aciodrv_device_msg_counter++;
int send_size = offsetof(struct ac_io_message, cmd.raw) + msg->cmd.nbytes;
if (aciodrv_device_send(
(uint8_t *) msg,
offsetof(struct ac_io_message, cmd.raw) + msg->cmd.nbytes) <= 0) {
#ifdef AC_IO_MSG_LOG
log_info(
"Beginning send on %d: %04x (%d b)",
msg->addr,
msg->cmd.code,
send_size);
#endif
if (aciodrv_device_send((uint8_t *) msg, send_size) <= 0) {
return false;
}
uint16_t req_code = msg->cmd.code;
#ifdef AC_IO_MSG_LOG
log_info("Beginning recv: (%d b)", resp_size);
#endif
if (aciodrv_device_receive((uint8_t *) msg, resp_size) <= 0) {
return false;
}

View File

@@ -37,7 +37,12 @@ static bool aciodrv_kfca_watchdog_start(uint8_t node_id)
*/
}
static bool aciodrv_kfca_amp(uint8_t node_id)
bool aciodrv_kfca_amp(
uint8_t node_id,
uint8_t primary,
uint8_t headphone,
uint8_t unused,
uint8_t subwoofer)
{
struct ac_io_message msg;
@@ -45,12 +50,10 @@ static bool aciodrv_kfca_amp(uint8_t node_id)
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_AMP_CONTROL);
msg.cmd.nbytes = 4;
// yes this sets the amp to 100% volume
// TODO: expose this to sdvxio instead at some point
msg.cmd.raw[0] = 0;
msg.cmd.raw[1] = 0;
msg.cmd.raw[2] = 0;
msg.cmd.raw[3] = 0;
msg.cmd.raw[0] = primary;
msg.cmd.raw[1] = headphone;
msg.cmd.raw[2] = unused;
msg.cmd.raw[3] = subwoofer;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
@@ -69,7 +72,7 @@ bool aciodrv_kfca_init(uint8_t node_id)
return false;
}
if (!aciodrv_kfca_amp(node_id)) {
if (!aciodrv_kfca_amp(node_id, 0, 0, 0, 0)) {
return false;
}

View File

@@ -30,4 +30,22 @@ bool aciodrv_kfca_poll(
const struct ac_io_kfca_poll_out *pout,
struct ac_io_kfca_poll_in *pin);
/**
* Set the KFCA digital amp level
*
* @param node_id Id of the node to query (0 based).
* @param primary primary volume (96-0)
* @param headphone headphone volume (96-0)
* @param unused unknown volume (96-0) (unused)
* @param subwoofer subwoofer volume (96-0)
* @return True on success, false on error.
* @note Note 96 (or 100?) is lowest volume level, 0 is highest
*/
bool aciodrv_kfca_amp(
uint8_t node_id,
uint8_t primary,
uint8_t headphone,
uint8_t unused,
uint8_t subwoofer);
#endif

View File

@@ -30,8 +30,16 @@ void ac_io_emu_init(struct ac_io_emu *emu, const wchar_t *filename)
log_assert(emu != NULL);
log_assert(filename != NULL);
HRESULT hr;
memset(emu, 0, sizeof(*emu));
emu->fd = iohook_open_dummy_fd();
hr = iohook_open_nul_fd(&emu->fd);
if (hr != S_OK) {
log_fatal("Opening nul fd failed: %08lx", hr);
}
emu->wfilename = wstr_dup(filename);
wstr_narrow(filename, &emu->filename);
ac_io_in_init(&emu->in);

View File

@@ -1,5 +1,6 @@
#define LOG_MODULE "acioemu-hdxs"
#include "acio/hdxs.h"
#include "acio/acio.h"
#include "acioemu/emu.h"
@@ -18,12 +19,20 @@ static void ac_io_emu_hdxs_send_status(
const struct ac_io_message *req,
uint8_t status);
void ac_io_emu_hdxs_init(struct ac_io_emu_hdxs *hdxs, struct ac_io_emu *emu)
void ac_io_emu_hdxs_init(
struct ac_io_emu_hdxs *hdxs,
struct ac_io_emu *emu,
acio_hdxs_dispatcher lights_dispatcher)
{
log_assert(hdxs != NULL);
log_assert(emu != NULL);
if (lights_dispatcher == NULL) {
log_warning("NULL lights_dispatcher, HDXS light output won't work");
}
hdxs->emu = emu;
hdxs->lights_dispatcher = lights_dispatcher;
}
void ac_io_emu_hdxs_dispatch_request(
@@ -51,9 +60,19 @@ void ac_io_emu_hdxs_dispatch_request(
case AC_IO_CMD_CLEAR:
log_misc("AC_IO_CMD_CLEAR(%d)", req->addr);
ac_io_emu_hdxs_send_status(hdxs, req, 0x00);
break;
case AC_IO_HDXS_CMD_SET_OUTPUTS:
if (hdxs->lights_dispatcher != NULL) {
hdxs->lights_dispatcher(hdxs, req);
}
ac_io_emu_hdxs_send_status(hdxs, req, 0x00);
break;
case 0x110:
case 0x112:
case 0x128:
ac_io_emu_hdxs_send_status(hdxs, req, 0x00);
@@ -86,11 +105,11 @@ static void ac_io_emu_hdxs_cmd_send_version(
resp.cmd.version.type = ac_io_u32(AC_IO_NODE_TYPE_LED_STRIP);
resp.cmd.version.flag = 0x00;
resp.cmd.version.major = 0x01;
resp.cmd.version.minor = 0x06;
resp.cmd.version.revision = 0x00;
resp.cmd.version.minor = 0x00;
resp.cmd.version.revision = 0x01;
memcpy(
resp.cmd.version.product_code,
"HDXS",
"HDXB",
sizeof(resp.cmd.version.product_code));
strncpy(resp.cmd.version.date, __DATE__, sizeof(resp.cmd.version.date));
strncpy(resp.cmd.version.time, __TIME__, sizeof(resp.cmd.version.time));

View File

@@ -5,12 +5,21 @@
#include "acioemu/emu.h"
struct ac_io_emu_hdxs;
struct ac_io_message;
typedef void (*acio_hdxs_dispatcher)(
struct ac_io_emu_hdxs *emu, const struct ac_io_message *req);
struct ac_io_emu_hdxs {
struct ac_io_emu *emu;
// TODO ops vtbl
acio_hdxs_dispatcher lights_dispatcher;
};
void ac_io_emu_hdxs_init(struct ac_io_emu_hdxs *hdxs, struct ac_io_emu *emu);
void ac_io_emu_hdxs_init(
struct ac_io_emu_hdxs *hdxs,
struct ac_io_emu *emu,
acio_hdxs_dispatcher lights_dispatcher);
void ac_io_emu_hdxs_dispatch_request(
struct ac_io_emu_hdxs *hdxs, const struct ac_io_message *req);

View File

@@ -14,6 +14,7 @@
#include "bemanitools/eamio.h"
#include "util/crc.h"
#include "util/time.h"
enum ac_io_icca_subcmd {
@@ -41,7 +42,8 @@ static void ac_io_emu_icca_cmd_send_version(
static void ac_io_emu_icca_send_state(
struct ac_io_emu_icca *icca,
const struct ac_io_message *req,
uint64_t delay_us);
uint64_t delay_us,
bool encrypted);
static void ac_io_emu_icca_send_empty(
struct ac_io_emu_icca *icca, const struct ac_io_message *req);
@@ -51,6 +53,12 @@ static void ac_io_emu_icca_send_status(
const struct ac_io_message *req,
uint8_t status);
static void ac_io_emu_icca_cipher(
struct ac_io_emu_icca *icca, uint8_t *data, size_t length);
static void ac_io_emu_icca_cipher_set_key(
struct ac_io_emu_icca *icca, const struct ac_io_message *req);
void ac_io_emu_icca_init(
struct ac_io_emu_icca *icca, struct ac_io_emu *emu, uint8_t unit_no)
{
@@ -59,6 +67,15 @@ void ac_io_emu_icca_init(
icca->unit_no = unit_no;
// queue must be started
icca->fault = true;
// default to 1.6.0
icca->version = v160;
}
void ac_io_emu_icca_set_version(
struct ac_io_emu_icca *icca, enum ac_io_emu_icca_version version)
{
icca->version = version;
}
void ac_io_emu_icca_dispatch_request(
@@ -123,7 +140,7 @@ void ac_io_emu_icca_dispatch_request(
break;
case AC_IO_ICCA_CMD_ENGAGE:
ac_io_emu_icca_send_state(icca, req, 0);
ac_io_emu_icca_send_state(icca, req, 0, false);
break;
@@ -174,6 +191,7 @@ void ac_io_emu_icca_dispatch_request(
break;
}
case AC_IO_ICCA_CMD_POLL_ENCRYPTED:
case AC_IO_ICCA_CMD_POLL:
delay_us = time_get_elapsed_us(
time_get_counter() - icca->time_counter_last_poll);
@@ -185,13 +203,26 @@ void ac_io_emu_icca_dispatch_request(
}
icca->time_counter_last_poll = time_get_counter();
ac_io_emu_icca_send_state(icca, req, delay_us);
bool encrypted = cmd_code == AC_IO_ICCA_CMD_POLL_ENCRYPTED;
ac_io_emu_icca_send_state(icca, req, delay_us, encrypted);
break;
case AC_IO_ICCA_CMD_POLL_FELICA:
icca->detected_new_reader = true;
ac_io_emu_icca_send_status(icca, req, 0x01);
if (icca->version == v170) {
ac_io_emu_icca_send_empty(icca, req);
} else {
ac_io_emu_icca_send_status(icca, req, 0x01);
}
break;
case AC_IO_ICCA_CMD_KEY_EXCHANGE:
icca->detected_new_reader = true;
log_misc("AC_IO_ICCA_CMD_KEY_EXCHANGE(%d)", req->addr);
ac_io_emu_icca_cipher_set_key(icca, req);
break;
@@ -215,10 +246,27 @@ static void ac_io_emu_icca_cmd_send_version(
resp.cmd.seq_no = req->cmd.seq_no;
resp.cmd.nbytes = sizeof(resp.cmd.version);
resp.cmd.version.type = ac_io_u32(AC_IO_NODE_TYPE_ICCA);
resp.cmd.version.flag = 0x00;
resp.cmd.version.major = 0x01;
resp.cmd.version.minor = 0x06;
if (icca->version == v150) {
log_warning(
"ICCA v1.5.0 emulation requested, please remove this log once implemented");
resp.cmd.version.minor = 0x05;
} else if (icca->version == v160) {
resp.cmd.version.minor = 0x06;
} else if (icca->version == v170) {
resp.cmd.version.minor = 0x07;
} else {
// probably log invalid version here
log_warning(
"Unknown ICCA version: %d emulation requested",
icca->version);
}
resp.cmd.version.revision = 0x00;
memcpy(
resp.cmd.version.product_code,
"ICCA",
@@ -261,7 +309,8 @@ static void ac_io_emu_icca_send_status(
static void ac_io_emu_icca_send_state(
struct ac_io_emu_icca *icca,
const struct ac_io_message *req,
uint64_t delay_us)
uint64_t delay_us,
bool encrypted)
{
struct ac_io_message resp;
struct ac_io_icca_state *body;
@@ -319,7 +368,10 @@ static void ac_io_emu_icca_send_state(
} else if (card_full_insert) {
body->status_code = AC_IO_ICCA_STATUS_GOT_UID;
} else {
if (icca->detected_new_reader) {
if (icca->detected_new_reader && icca->version == v170) {
// else we get a power failure?
body->status_code = 0;
} else if (icca->detected_new_reader) {
body->status_code = AC_IO_ICCA_STATUS_IDLE_NEW;
} else {
body->status_code = AC_IO_ICCA_STATUS_IDLE;
@@ -384,5 +436,88 @@ static void ac_io_emu_icca_send_state(
body->status_code = AC_IO_ICCA_STATUS_FAULT;
}
if (encrypted) {
size_t base_state_sz = sizeof(struct ac_io_icca_state);
resp.cmd.nbytes = base_state_sz + 2;
if (!icca->cipher_started) {
log_warning("No crypto keys set for unit %d", icca->unit_no);
} else {
uint16_t crc = crc16_msb(resp.cmd.raw, base_state_sz, 0);
resp.cmd.raw[base_state_sz + 0] = (crc >> 8) & 0xFF;
resp.cmd.raw[base_state_sz + 1] = crc & 0xFF;
ac_io_emu_icca_cipher(icca, resp.cmd.raw, 18);
}
}
ac_io_emu_response_push(icca->emu, &resp, delay_us);
}
static void ac_io_emu_icca_cipher_shift_keys(struct ac_io_emu_icca *icca)
{
uint32_t key4_old = icca->cipher_keys[3];
uint32_t key_new = (key4_old << 11) ^ key4_old;
uint32_t key1_old = icca->cipher_keys[0];
// shift keys up
icca->cipher_keys[3] = icca->cipher_keys[2];
icca->cipher_keys[2] = icca->cipher_keys[1];
icca->cipher_keys[1] = icca->cipher_keys[0];
icca->cipher_keys[0] =
((((key1_old >> 11) ^ key_new) >> 8) ^ key_new ^ key1_old);
}
static void
ac_io_emu_icca_cipher(struct ac_io_emu_icca *icca, uint8_t *data, size_t length)
{
for (size_t i = 0; i < length; i++) {
uint8_t count4 = i % 4;
// shift keys every 4 bytes
if (count4 == 0) {
ac_io_emu_icca_cipher_shift_keys(icca);
}
// process data
data[i] =
(uint8_t)(icca->cipher_keys[0] >> (((3 - count4) << 3)) ^ data[i]);
}
}
static void ac_io_emu_icca_cipher_set_key(
struct ac_io_emu_icca *icca, const struct ac_io_message *req)
{
struct ac_io_message resp;
resp.addr = req->addr | AC_IO_RESPONSE_FLAG;
resp.cmd.code = req->cmd.code;
resp.cmd.seq_no = req->cmd.seq_no;
resp.cmd.nbytes = 4; // 4 bytes, uint32_t
uint32_t host_key = 0x00000000;
host_key |= req->cmd.raw[0] << 24;
host_key |= req->cmd.raw[1] << 16;
host_key |= req->cmd.raw[2] << 8;
host_key |= req->cmd.raw[3];
// TODO: should probably RNG this
uint32_t reader_key = 0x14243444;
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;
// so I looked these constants up, this isn't actually a secure key
// generator it's actually Marsaglia's "KISS" algorithm with different
// initial states
icca->cipher_keys[0] = reader_key ^ 0x5491333;
icca->cipher_keys[1] = host_key ^ 0x1F123BB5;
icca->cipher_keys[2] = reader_key ^ 0x159A55E5;
icca->cipher_keys[3] = host_key ^ 0x75BCD15;
log_misc("keys set to: H: %08x R: %08x", host_key, reader_key);
ac_io_emu_response_push(icca->emu, &resp, 0);
icca->cipher_started = true;
}

View File

@@ -6,6 +6,12 @@
#include "acioemu/emu.h"
enum ac_io_emu_icca_version {
v150 = 0x5,
v160 = 0x6,
v170 = 0x7,
};
struct ac_io_emu_icca {
struct ac_io_emu *emu;
uint8_t unit_no;
@@ -20,11 +26,19 @@ struct ac_io_emu_icca {
bool keypad_started;
bool polling_started;
uint64_t time_counter_last_poll;
enum ac_io_emu_icca_version version;
bool cipher_started;
uint32_t cipher_keys[4];
};
void ac_io_emu_icca_init(
struct ac_io_emu_icca *icca, struct ac_io_emu *emu, uint8_t unit_no);
// optional, call after init to override default version
void ac_io_emu_icca_set_version(
struct ac_io_emu_icca *icca, enum ac_io_emu_icca_version version);
void ac_io_emu_icca_dispatch_request(
struct ac_io_emu_icca *icca, const struct ac_io_message *req);

View File

@@ -1,10 +1,12 @@
exes += aciotest
libs_aciotest := \
bio2drv \
aciodrv \
util \
src_aciotest := \
icca.c \
kfca.c \
bi2a-sdvx.c \
main.c \

View File

@@ -0,0 +1,58 @@
#include "aciotest/bi2a-sdvx.h"
#include "acio/acio.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bio2drv/bi2a-sdvx.h"
bool aciotest_bi2a_sdvx_handler_init(uint8_t node_id, void **ctx)
{
*ctx = malloc(sizeof(uint32_t));
*((uint32_t *) *ctx) = 0;
return bio2drv_bi2a_sdvx_init(node_id);
}
bool aciotest_bi2a_sdvx_handler_update(uint8_t node_id, void *ctx)
{
struct bi2a_sdvx_state_in pin;
struct bi2a_sdvx_state_out pout;
memset(&pout, 0, sizeof(pout));
if (!bio2drv_bi2a_sdvx_poll(node_id, &pout, &pin)) {
return false;
}
pin.raw[0] = ac_io_u16(pin.raw[0]);
pin.raw[1] = ac_io_u16(pin.raw[1]);
printf(
">>> BI2A (SDVX) %d:\n"
"BTN A B C D: %d %d %d %d\n"
"FX-L R: %d %d\n"
"VOL L: %d\n"
"VOL R: %d\n"
"START COIN TEST SERV REC HP: %d %d %d %d %d %d\n",
node_id,
pin.buttons_1.b_a,
pin.buttons_1.b_b,
pin.buttons_1.b_c,
pin.buttons_1.b_d,
pin.buttons_1.b_fxl,
pin.buttons_2.b_fxr,
pin.analogs[0].a_val,
pin.analogs[1].a_val,
pin.buttons_1.b_start,
pin.analogs[0].a_coin,
pin.analogs[0].a_test,
pin.analogs[0].a_service,
pin.buttons_1.b_recorder,
pin.buttons_1.b_headphone);
return true;
}

View File

@@ -0,0 +1,10 @@
#ifndef ACIOTEST_BI2A_SDVX_H
#define ACIOTEST_BI2A_SDVX_H
#include <stdbool.h>
#include <stdint.h>
bool aciotest_bi2a_sdvx_handler_init(uint8_t node_id, void **ctx);
bool aciotest_bi2a_sdvx_handler_update(uint8_t node_id, void *ctx);
#endif

View File

@@ -6,6 +6,7 @@
#include "aciodrv/device.h"
#include "aciotest/bi2a-sdvx.h"
#include "aciotest/handler.h"
#include "aciotest/icca.h"
#include "aciotest/kfca.h"
@@ -13,6 +14,7 @@
#include "util/log.h"
static uint8_t aciotest_cnt = 0;
static uint8_t bi2a_mode = 0;
/**
* Enumerate supported ACIO nodes based on their product id.
@@ -35,6 +37,17 @@ static bool aciotest_assign_handler(
return true;
}
if (!memcmp(product, "BI2A", 4)) {
if (bi2a_mode == 0) {
handler->init = aciotest_bi2a_sdvx_handler_init;
handler->update = aciotest_bi2a_sdvx_handler_update;
return true;
} else {
printf("Unknown BI2A device specified");
}
}
return false;
}
@@ -125,7 +138,7 @@ int main(int argc, char **argv)
}
/* avoid cpu banging */
Sleep(20);
Sleep(30);
}
return 0;

10
src/main/asio/Module.mk Normal file
View File

@@ -0,0 +1,10 @@
libs += asio
libs_asio := \
hook \
hooklib \
util \
src_asio := \
asio-reghook.c \
config-asio.c \

View File

@@ -0,0 +1,199 @@
#define LOG_MODULE "asio-reghook"
// clang-format off
// Don't format because the order is important here
#include <windows.h>
#include <initguid.h>
// clang-format on
#include <winreg.h>
#include <stdio.h>
#include "hook/com-proxy.h"
#include "hook/table.h"
#include "asio/asio-reghook.h"
#include "util/defs.h"
#include "util/log.h"
#include "util/str.h"
#include "util/time.h"
// MAXDRVNAMELEN
#define ASIO_NAME_STRING_SIZE 128
static char asio_expected_name[ASIO_NAME_STRING_SIZE] = "XONAR SOUND CARD(64)";
static char asio_target_name[ASIO_NAME_STRING_SIZE] = "XONAR SOUND CARD(64)";
static HKEY asio_root_key;
static HKEY asio_sub_key;
LSTATUS my_RegOpenKeyA(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult);
LSTATUS my_RegEnumKeyA(HKEY hKey, DWORD dwIndex, LPSTR lpName, DWORD cchName);
LSTATUS my_RegOpenKeyExA(
HKEY hKey,
LPCSTR lpSubKey,
DWORD ulOptions,
REGSAM samDesired,
PHKEY phkResult);
LSTATUS my_RegQueryValueExA(
HKEY hKey,
LPCSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData);
LSTATUS my_RegCloseKey(HKEY hKey);
LSTATUS (*real_RegOpenKeyA)(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult);
LSTATUS (*real_RegEnumKeyA)
(HKEY hKey, DWORD dwIndex, LPSTR lpName, DWORD cchName);
LSTATUS (*real_RegOpenKeyExA)
(HKEY hKey,
LPCSTR lpSubKey,
DWORD ulOptions,
REGSAM samDesired,
PHKEY phkResult);
LSTATUS (*real_RegQueryValueExA)
(HKEY hKey,
LPCSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData);
LSTATUS (*real_RegCloseKey)(HKEY hKey);
static const struct hook_symbol asio_reghook_advapi32_syms[] = {
{.name = "RegOpenKeyA",
.patch = my_RegOpenKeyA,
.link = (void **) &real_RegOpenKeyA},
{.name = "RegEnumKeyA",
.patch = my_RegEnumKeyA,
.link = (void **) &real_RegEnumKeyA},
{.name = "RegOpenKeyExA",
.patch = my_RegOpenKeyExA,
.link = (void **) &real_RegOpenKeyExA},
{.name = "RegQueryValueExA",
.patch = my_RegQueryValueExA,
.link = (void **) &real_RegQueryValueExA},
{.name = "RegCloseKey",
.patch = my_RegCloseKey,
.link = (void **) &real_RegCloseKey},
};
LSTATUS my_RegOpenKeyA(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult)
{
LSTATUS result = real_RegOpenKeyA(hKey, lpSubKey, phkResult);
if (!strcmp("software\\asio", lpSubKey)) {
log_info("ASIO root key found");
asio_root_key = *phkResult;
}
return result;
}
LSTATUS my_RegEnumKeyA(HKEY hKey, DWORD dwIndex, LPSTR lpName, DWORD cchName)
{
LSTATUS result = real_RegEnumKeyA(hKey, dwIndex, lpName, cchName);
if (hKey == asio_root_key) {
if (!strcmp(asio_target_name, lpName)) {
log_info(
"Replacing key [%s] with [%s]",
asio_target_name,
asio_expected_name);
strncpy(lpName, asio_expected_name, cchName);
}
}
return result;
}
LSTATUS my_RegOpenKeyExA(
HKEY hKey,
LPCSTR lpSubKey,
DWORD ulOptions,
REGSAM samDesired,
PHKEY phkResult)
{
if (hKey == asio_root_key) {
if (!strcmp(asio_expected_name, lpSubKey)) {
// swap to the real one so the call succeeds
LSTATUS result = real_RegOpenKeyExA(
hKey, asio_target_name, ulOptions, samDesired, phkResult);
asio_sub_key = *phkResult;
log_info("ASIO device key found");
return result;
}
}
return real_RegOpenKeyExA(hKey, lpSubKey, ulOptions, samDesired, phkResult);
}
LSTATUS my_RegQueryValueExA(
HKEY hKey,
LPCSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData)
{
DWORD lpcbData_orig = *lpcbData;
LSTATUS result = real_RegQueryValueExA(
hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
if (result == ERROR_SUCCESS) {
if (hKey == asio_sub_key) {
if (!strcmp("description", lpValueName)) {
log_info(
"Replacing description [%s] with [%s]",
lpData,
asio_expected_name);
strncpy((char *) lpData, asio_expected_name, lpcbData_orig);
}
}
}
return result;
}
LSTATUS my_RegCloseKey(HKEY hKey)
{
if (hKey == asio_root_key) {
asio_root_key = NULL;
}
if (hKey == asio_sub_key) {
asio_sub_key = NULL;
}
return real_RegCloseKey(hKey);
}
void asio_reghook_init(const char *expected_name, const char *target_name)
{
strncpy(asio_expected_name, expected_name, ASIO_NAME_STRING_SIZE - 1);
strncpy(asio_target_name, target_name, ASIO_NAME_STRING_SIZE - 1);
asio_expected_name[ASIO_NAME_STRING_SIZE - 1] = '\0';
asio_target_name[ASIO_NAME_STRING_SIZE - 1] = '\0';
hook_table_apply(
NULL,
"Advapi32.dll",
asio_reghook_advapi32_syms,
lengthof(asio_reghook_advapi32_syms));
log_info("Inserted reg hooks for ASIO override");
}

View File

@@ -0,0 +1,6 @@
#ifndef IASIO_REG_HOOK_H
#define IASIO_REG_HOOK_H
void asio_reghook_init(const char *expected_name, const char *target_name);
#endif

View File

@@ -0,0 +1,75 @@
#include "cconfig/cconfig-util.h"
#include "asio/config-asio.h"
#include "util/log.h"
#define ASIOHOOK_CONFIG_IO_FORCE_ASIO_KEY "asio.force_asio"
#define ASIOHOOK_CONFIG_IO_FORCE_WASAPI_KEY "asio.force_wasapi"
#define ASIOHOOK_CONFIG_IO_ASIO_DEVICE_NAME_KEY "asio.device_name"
#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)"
void asiohook_config_init(struct cconfig *config)
{
cconfig_util_set_bool(
config,
ASIOHOOK_CONFIG_IO_FORCE_ASIO_KEY,
ASIOHOOK_CONFIG_IO_DEFAULT_FORCE_ASIO_VALUE,
"Force ASIO audio mode/device (if applicable)");
cconfig_util_set_bool(
config,
ASIOHOOK_CONFIG_IO_FORCE_WASAPI_KEY,
ASIOHOOK_CONFIG_IO_DEFAULT_FORCE_WASAPI_VALUE,
"Force WASAPI audio mode (if applicable)");
cconfig_util_set_str(
config,
ASIOHOOK_CONFIG_IO_ASIO_DEVICE_NAME_KEY,
ASIOHOOK_CONFIG_IO_DEFAULT_ASIO_DEVICE_NAME_VALUE,
"The ASIO device name to use");
}
void asiohook_config_asio_get(
struct asiohook_config_asio *config_asio, struct cconfig *config)
{
if (!cconfig_util_get_bool(
config,
ASIOHOOK_CONFIG_IO_FORCE_ASIO_KEY,
&config_asio->force_asio,
ASIOHOOK_CONFIG_IO_DEFAULT_FORCE_ASIO_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%d'",
ASIOHOOK_CONFIG_IO_FORCE_ASIO_KEY,
ASIOHOOK_CONFIG_IO_DEFAULT_FORCE_ASIO_VALUE);
}
if (!cconfig_util_get_bool(
config,
ASIOHOOK_CONFIG_IO_FORCE_WASAPI_KEY,
&config_asio->force_wasapi,
ASIOHOOK_CONFIG_IO_DEFAULT_FORCE_WASAPI_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%d'",
ASIOHOOK_CONFIG_IO_FORCE_WASAPI_KEY,
ASIOHOOK_CONFIG_IO_DEFAULT_FORCE_WASAPI_VALUE);
}
if (!cconfig_util_get_str(
config,
ASIOHOOK_CONFIG_IO_ASIO_DEVICE_NAME_KEY,
config_asio->replacement_name,
sizeof(config_asio->replacement_name) - 1,
ASIOHOOK_CONFIG_IO_DEFAULT_ASIO_DEVICE_NAME_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%s'",
ASIOHOOK_CONFIG_IO_ASIO_DEVICE_NAME_KEY,
ASIOHOOK_CONFIG_IO_DEFAULT_ASIO_DEVICE_NAME_VALUE);
}
}

View File

@@ -0,0 +1,19 @@
#ifndef ASIOHOOK_CONFIG_IO_H
#define ASIOHOOK_CONFIG_IO_H
#include <windows.h>
#include "cconfig/cconfig.h"
struct asiohook_config_asio {
bool force_asio;
bool force_wasapi;
char replacement_name[128];
};
void asiohook_config_init(struct cconfig *config);
void asiohook_config_asio_get(
struct asiohook_config_asio *config_asio, struct cconfig *config);
#endif

View File

@@ -32,8 +32,7 @@ enum ddr_pad_bit {
DDR_P1_MENU_DOWN = 0x01,
};
/* p3io controls menu btn and marquee lights
extio controls neons and stage lights. */
// see the functions below for more information
enum p3io_light_bit {
LIGHT_P1_MENU = 0x00,
@@ -41,7 +40,32 @@ enum p3io_light_bit {
LIGHT_P2_LOWER_LAMP = 0x04,
LIGHT_P2_UPPER_LAMP = 0x05,
LIGHT_P1_LOWER_LAMP = 0x06,
LIGHT_P1_UPPER_LAMP = 0x07
LIGHT_P1_UPPER_LAMP = 0x07,
};
enum hdxs_light_bit {
LIGHT_HD_P1_START = 0x08,
LIGHT_HD_P1_UP_DOWN = 0x09,
LIGHT_HD_P1_LEFT_RIGHT = 0x0A,
LIGHT_HD_P2_START = 0x0B,
LIGHT_HD_P2_UP_DOWN = 0x0C,
LIGHT_HD_P2_LEFT_RIGHT = 0x0D,
};
// the indexing starts from 0x20 if you're looking in geninput
enum hdxs_rgb_light_idx {
LIGHT_HD_P1_SPEAKER_F_R = 0x00,
LIGHT_HD_P1_SPEAKER_F_G = 0x01,
LIGHT_HD_P1_SPEAKER_F_B = 0x02,
LIGHT_HD_P2_SPEAKER_F_R = 0x03,
LIGHT_HD_P2_SPEAKER_F_G = 0x04,
LIGHT_HD_P2_SPEAKER_F_B = 0x05,
LIGHT_HD_P1_SPEAKER_W_R = 0x06,
LIGHT_HD_P1_SPEAKER_W_G = 0x07,
LIGHT_HD_P1_SPEAKER_W_B = 0x08,
LIGHT_HD_P2_SPEAKER_W_R = 0x09,
LIGHT_HD_P2_SPEAKER_W_G = 0x0A,
LIGHT_HD_P2_SPEAKER_W_B = 0x0B,
};
enum extio_light_bit {
@@ -81,9 +105,26 @@ 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);
/* The following are optional to implement, and allow lights to be set and
emulated as needed */
/* used to set pad lights, as well as the bass neon on SD cabs */
void ddr_io_set_lights_extio(uint32_t extio_lights);
/* used to set SD panel lights, and HD spot lights */
void ddr_io_set_lights_p3io(uint32_t p3io_lights);
/* used to set HD cab front panel lights */
void ddr_io_set_lights_hdxs_panel(uint32_t hdxs_lights);
/* used to set HD cab speaker RGB lights */
void ddr_io_set_lights_hdxs_rgb(uint8_t idx, uint8_t r, uint8_t g, uint8_t b);
void ddr_io_fini(void);
#endif

View File

@@ -98,4 +98,12 @@ uint16_t sdvx_io_get_input_gpio(uint8_t gpio_bank);
uint16_t sdvx_io_get_spinner_pos(uint8_t spinner_no);
/* Sets the volume of the digital amps if possible.
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);
#endif

View File

@@ -1,18 +1,7 @@
#ifndef IIDXHOOK_BI2A_H
#define IIDXHOOK_BI2A_H
#ifndef BIO2_BI2A_IIDX
#define BIO2_BI2A_IIDX
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "bio2emu/emu.h"
enum bio2_iidx_cmd {
// Custom Stuff
BIO2_BI2A_CMD_UNK_0100 = 0x0100,
BIO2_BI2A_CMD_UNK_0120 = 0x0120,
BIO2_BI2A_CMD_POLL = 0x0152,
};
#include "bio2/bio2.h"
#pragma pack(push, 1)
struct bi2a_iidx_slider {
@@ -114,8 +103,4 @@ _Static_assert(
"bi2a_iidx_state_out is the wrong size");
#pragma pack(pop)
void bio2_emu_bi2a_init(struct bio2emu_port *in, bool disable_poll_limiter);
void bio2_emu_bi2a_dispatch_request(
struct bio2emu_port *bio2port, const struct ac_io_message *req);
#endif

75
src/main/bio2/bi2a-sdvx.h Normal file
View File

@@ -0,0 +1,75 @@
#ifndef BIO2_BI2A_SDVX
#define BIO2_BI2A_SDVX
#include "bio2/bio2.h"
#pragma pack(push, 1)
struct bi2a_sdvx_analog {
uint16_t unk1 : 1;
uint16_t a_coin : 1;
uint16_t a_service : 1;
uint16_t a_test : 1;
uint16_t unk2 : 2;
uint16_t a_val : 10;
};
struct bi2a_sdvx_buttons1 {
uint8_t b_fxl : 1;
uint8_t b_d : 1;
uint8_t b_c : 1;
uint8_t b_b : 1;
uint8_t b_a : 1;
uint8_t b_start : 1;
uint8_t b_recorder : 1;
uint8_t b_headphone : 1;
};
struct bi2a_sdvx_buttons2 {
uint8_t unk : 5;
uint8_t b_ex2 : 1;
uint8_t b_ex1 : 1;
uint8_t b_fxr : 1;
};
struct bi2a_sdvx_state_in {
union {
uint16_t raw[8];
struct {
struct bi2a_sdvx_analog analogs[4];
uint8_t unk_1; // coin mech?
struct bi2a_sdvx_buttons1 buttons_1;
struct bi2a_sdvx_buttons2 buttons_2;
uint8_t unk_2[5];
};
};
};
struct bi2a_sdvx_state_out {
uint8_t unk1[2];
uint8_t c_block;
uint8_t woof_r;
uint8_t woof_g;
uint8_t unk2;
uint8_t woof_b;
uint8_t controller[3];
uint8_t unk3;
uint8_t gpio[7]; // START, ABCD, FXL, FXR
uint8_t unk4[3];
uint8_t generator[3];
uint8_t unk5[3];
uint8_t gpio2[3]; // pop, titleL, titleR
uint8_t unk6;
uint8_t wingUpper[3];
uint8_t wingLower[3];
uint8_t unk7[3];
};
_Static_assert(
sizeof(struct bi2a_sdvx_state_in) == 16,
"bi2a_sdvx_state_in is the wrong size");
_Static_assert(
sizeof(struct bi2a_sdvx_state_out) == 40,
"bi2a_sdvx_state_out is the wrong size");
#pragma pack(pop)
#endif

15
src/main/bio2/bio2.h Normal file
View File

@@ -0,0 +1,15 @@
#ifndef BIO2_BIO2
#define BIO2_BIO2
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
enum bio2_bi2a_cmd {
// Custom Stuff
BIO2_BI2A_CMD_UNK_0100 = 0x0100,
BIO2_BI2A_CMD_UNK_0120 = 0x0120,
BIO2_BI2A_CMD_POLL = 0x0152, // For IIDX
};
#endif

View File

@@ -0,0 +1,9 @@
libs += bio2drv
libs_bio2drv := \
aciodrv
src_bio2drv := \
detect.c \
config-bio2.c \
bi2a-sdvx.c \

View File

@@ -0,0 +1,138 @@
#define LOG_MODULE "bio2drv-bi2a_sdvx"
#include "bio2drv/bi2a-sdvx.h"
#include <stdio.h>
#include <string.h>
#include "aciodrv/device.h"
#include "util/log.h"
// this is probably InitIO
static bool bio2drv_bi2a_sdvx_init_io(uint8_t node_id)
{
struct ac_io_message msg;
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_CLEAR);
msg.cmd.nbytes = 1;
msg.cmd.count = 0x3B;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Init node failed");
return 0;
}
log_warning("Init of node %d, status: %d", node_id, msg.cmd.status);
return 1;
}
static bool bio2drv_bi2a_sdvx_watchdog_start(uint8_t node_id)
{
// exit early and don't actually call watchdog
// the watchdog call actually returns different sized packets depending on
// the state this results in an issue during packet processing (see: #68)
return true;
/*
struct ac_io_message msg;
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_WATCHDOG);
msg.cmd.nbytes = 2;
msg.cmd.nbytes = 2;
// uint16_t: 6000
msg.cmd.raw[0] = 23;
msg.cmd.raw[1] = 112;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 2
)) {
log_warning("Starting watchdog failed"); return false;
}
log_warning("Started watchdog of node %d, status: %d",
node_id, msg.cmd.status);
return true;
*/
}
bool bio2drv_bi2a_sdvx_amp(
uint8_t node_id,
uint8_t unused_1,
uint8_t unused_2,
uint8_t left,
uint8_t right)
{
struct ac_io_message msg;
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_AMP_CONTROL);
msg.cmd.nbytes = 4;
// the BIO2 DOES NOT MATCH THE KFCA for what these mean
// 0 and 1 are ignored, 2 and 3 seem to map to left/right for ALL 3 AMPS
// in the future, maybe use windows APIs and write the volume levels there
msg.cmd.raw[0] = unused_1;
msg.cmd.raw[1] = unused_2;
msg.cmd.raw[2] = left;
msg.cmd.raw[3] = right;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Setting AMP failed");
return false;
}
log_warning("Started AMP node %d", node_id);
return true;
}
bool bio2drv_bi2a_sdvx_init(uint8_t node_id)
{
if (!bio2drv_bi2a_sdvx_init_io(node_id)) {
return false;
}
if (!bio2drv_bi2a_sdvx_watchdog_start(node_id)) {
return false;
}
if (!bio2drv_bi2a_sdvx_amp(node_id, 0, 0, 0, 0)) {
return false;
}
return true;
}
bool bio2drv_bi2a_sdvx_poll(
uint8_t node_id,
const struct bi2a_sdvx_state_out *pout,
struct bi2a_sdvx_state_in *pin)
{
struct ac_io_message msg;
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_POLL);
msg.cmd.nbytes = sizeof(*pout);
/* buffer size of data we expect */
*(struct bi2a_sdvx_state_out *) msg.cmd.raw = *pout;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) {
log_warning("Polling of node %d failed", node_id + 1);
return false;
}
if (pin != NULL) {
memcpy(pin, &msg.cmd.raw, sizeof(*pin));
}
return true;
}

View File

@@ -0,0 +1,51 @@
#ifndef BIO2DRV_BI2A_H
#define BIO2DRV_BI2A_H
#include "bio2/bi2a-sdvx.h"
/**
* Initialize a BI2A node.
*
* @param node_id Id of the node to initialize (0 based).
* @return True if successful, false on error.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool bio2drv_bi2a_sdvx_init(uint8_t node_id);
/**
* Poll the board
*
* @param node_id Id of the node to query (0 based).
* @param state Pointer to a state struct to return the current state to
* (optional, NULL for none).
* @return True on success, false on error.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool bio2drv_bi2a_sdvx_poll(
uint8_t node_id,
const struct bi2a_sdvx_state_out *pout,
struct bi2a_sdvx_state_in *pin);
/**
* Set the BIO2 BI2A SDVX digital amp level
*
* @param node_id Id of the node to query (0 based).
* @param primary primary volume (96-0)
* @param headphone headphone volume (96-0)
* @param unused unknown volume (96-0) (unused)
* @param subwoofer subwoofer volume (96-0)
* @return True on success, false on error.
* @note Note 96 is lowest volume level, 0 is highest
*/
bool bio2drv_bi2a_sdvx_amp(
uint8_t node_id,
uint8_t unused_1,
uint8_t unused_2,
uint8_t left,
uint8_t right);
#endif

View File

@@ -0,0 +1,75 @@
#include "cconfig/cconfig-util.h"
#include "bio2drv/config-bio2.h"
#include "util/log.h"
#define BIO2DRV_CONFIG_BIO2_AUTO_KEY "bio2.autodetect"
#define BIO2DRV_CONFIG_BIO2_PORT_KEY "bio2.port"
#define BIO2DRV_CONFIG_BIO2_BAUD_KEY "bio2.baud"
#define BIO2DRV_CONFIG_BIO2_DEFAULT_AUTO_VALUE true
#define BIO2DRV_CONFIG_BIO2_DEFAULT_PORT_VALUE "COM4"
#define BIO2DRV_CONFIG_BIO2_DEFAULT_BAUD_VALUE 115200
void bio2drv_config_bio2_init(struct cconfig *config)
{
cconfig_util_set_bool(
config,
BIO2DRV_CONFIG_BIO2_AUTO_KEY,
BIO2DRV_CONFIG_BIO2_DEFAULT_AUTO_VALUE,
"Autodetect BIO2 port (default: on)");
cconfig_util_set_str(
config,
BIO2DRV_CONFIG_BIO2_PORT_KEY,
BIO2DRV_CONFIG_BIO2_DEFAULT_PORT_VALUE,
"BIO2 serial port");
cconfig_util_set_int(
config,
BIO2DRV_CONFIG_BIO2_BAUD_KEY,
BIO2DRV_CONFIG_BIO2_DEFAULT_BAUD_VALUE,
"BIO2 bus baudrate (real devices expect 115200)");
}
void bio2drv_config_bio2_get(
struct bio2drv_config_bio2 *config_bio2, struct cconfig *config)
{
if (!cconfig_util_get_bool(
config,
BIO2DRV_CONFIG_BIO2_AUTO_KEY,
&config_bio2->autodetect,
BIO2DRV_CONFIG_BIO2_DEFAULT_AUTO_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%d'",
BIO2DRV_CONFIG_BIO2_AUTO_KEY,
BIO2DRV_CONFIG_BIO2_DEFAULT_AUTO_VALUE);
}
if (!cconfig_util_get_str(
config,
BIO2DRV_CONFIG_BIO2_PORT_KEY,
config_bio2->port,
sizeof(config_bio2->port) - 1,
BIO2DRV_CONFIG_BIO2_DEFAULT_PORT_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%s'",
BIO2DRV_CONFIG_BIO2_PORT_KEY,
BIO2DRV_CONFIG_BIO2_DEFAULT_PORT_VALUE);
}
if (!cconfig_util_get_int(
config,
BIO2DRV_CONFIG_BIO2_BAUD_KEY,
&config_bio2->baud,
BIO2DRV_CONFIG_BIO2_DEFAULT_BAUD_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%d'",
BIO2DRV_CONFIG_BIO2_BAUD_KEY,
BIO2DRV_CONFIG_BIO2_DEFAULT_BAUD_VALUE);
}
}

View File

@@ -0,0 +1,19 @@
#ifndef BIO2DRV_CONFIG_BIO2_H
#define BIO2DRV_CONFIG_BIO2_H
#include <windows.h>
#include "cconfig/cconfig.h"
struct bio2drv_config_bio2 {
bool autodetect;
char port[64];
int32_t baud;
};
void bio2drv_config_bio2_init(struct cconfig *config);
void bio2drv_config_bio2_get(
struct bio2drv_config_bio2 *config_bio2, struct cconfig *config);
#endif

163
src/main/bio2drv/detect.c Normal file
View File

@@ -0,0 +1,163 @@
#define LOG_MODULE "bio2drv-detect"
#include <initguid.h>
#include <windows.h>
#include <cfgmgr32.h>
#include <setupapi.h>
#include "bio2drv/detect.h"
#include <stdio.h>
#include <string.h>
#include "util/log.h"
DEFINE_GUID(
GUID_COM_BUS_ENUMERATOR,
0x4D36E978,
0xE325,
0x11CE,
0xBF,
0xC1,
0x08,
0x00,
0x2B,
0xE1,
0x03,
0x18);
static char work_buffer[0x400];
static bool check_property(
HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA PDeviceInfoData, DWORD property)
{
if (SetupDiGetDeviceRegistryPropertyA(
DeviceInfoSet,
PDeviceInfoData,
property,
NULL,
(BYTE *) work_buffer,
sizeof(work_buffer),
NULL)) {
if (strstr(work_buffer, "BIO2(VIDEO)")) {
log_info("Found matching device: %s", work_buffer);
return true;
}
}
log_info("Device with property: %s does not match", work_buffer);
return false;
}
static bool check_id(
HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA PDeviceInfoData)
{
if (CM_Get_Device_IDA(PDeviceInfoData->DevInst, work_buffer, sizeof(work_buffer), 0)) {
return false;
}
if (strstr(work_buffer, "VID_1CCF&PID_804C")) {
log_info("Found matching device: %s", work_buffer);
return true;
}
if (strstr(work_buffer, "VID_1CCF&PID_8040")) {
log_info("Found matching device: %s", work_buffer);
return true;
}
log_info("Device with ID: %s does not match", work_buffer);
return false;
}
static bool get_device_by_filter(
bool id_filter, DWORD property, size_t devnum, char *path, size_t length)
{
HDEVINFO DeviceInfoSet = SetupDiGetClassDevsA(
&GUID_COM_BUS_ENUMERATOR, NULL, NULL, DIGCF_PRESENT);
if (DeviceInfoSet == INVALID_HANDLE_VALUE) {
return false;
}
SP_DEVINFO_DATA DeviceInfoData;
ZeroMemory(&DeviceInfoData, sizeof(SP_DEVINFO_DATA));
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
DWORD idx = 0;
size_t num_found = 0;
while (SetupDiEnumDeviceInfo(DeviceInfoSet, idx, &DeviceInfoData)) {
HKEY DeviceRegKey = SetupDiOpenDevRegKey(
DeviceInfoSet,
&DeviceInfoData,
DICS_FLAG_GLOBAL,
0,
DIREG_DEV,
KEY_QUERY_VALUE);
if (DeviceRegKey) {
bool found = false;
log_info("Found a serial device at index: %ld", idx);
if (!id_filter) {
if (check_property(DeviceInfoSet, &DeviceInfoData, property)) {
found = true;
}
} else {
if (check_id(DeviceInfoSet, &DeviceInfoData)) {
found = true;
}
}
if (found) {
if (num_found == devnum) {
DWORD path_length = length;
RegQueryValueExA(
DeviceRegKey,
"PortName",
0,
NULL,
(BYTE *) path,
&path_length);
log_info("Using port: %s", path);
return true;
}
num_found++;
}
}
++idx;
}
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
log_warning("No matching device found");
return false;
}
void bio2drv_set_loggers(
log_formatter_t misc,
log_formatter_t info,
log_formatter_t warning,
log_formatter_t fatal)
{
log_to_external(misc, info, warning, fatal);
}
bool bio2drv_detect(
enum bio2drv_detect_mode mode, size_t index, char *path, size_t length)
{
if (mode == DETECT_DEVICEDESC) {
return get_device_by_filter(
false, SPDRP_DEVICEDESC, index, path, length);
} else if (mode == DETECT_FRIENDLYNAME) {
return get_device_by_filter(
false, SPDRP_FRIENDLYNAME, index, path, length);
} else if (mode == DETECT_DEVICEID) {
return get_device_by_filter(true, -1, index, path, length);
}
log_warning("Unknown autodetect mode: %d", mode);
return false;
}

23
src/main/bio2drv/detect.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef BIO2DRV_DETECT_H
#define BIO2DRV_DETECT_H
#include <stdbool.h>
#include "bemanitools/glue.h"
enum bio2drv_detect_mode {
DETECT_DEVICEDESC = 0x1, // look for serial devices containing BIO2(VIDEO)
DETECT_FRIENDLYNAME = 0x2, // look for serial devices containing BIO2(VIDEO)
DETECT_DEVICEID = 0x3, // look for serial devices by vid/pid
};
void bio2drv_set_loggers(
log_formatter_t misc,
log_formatter_t info,
log_formatter_t warning,
log_formatter_t fatal);
bool bio2drv_detect(
enum bio2drv_detect_mode mode, size_t devnum, char *path, size_t length);
#endif

View File

@@ -0,0 +1,7 @@
libs += bio2emu-iidx
libs_bio2emu-iidx := \
bio2emu \
src_bio2emu-iidx := \
bi2a.c \

View File

@@ -1,7 +1,6 @@
#define LOG_MODULE "bio2emu-bi2a"
#define LOG_MODULE "bio2emu-iidx"
#include "iidxhook8/bi2a.h"
#include "bio2emu/emu.h"
#include "bio2emu-iidx/bi2a.h"
#include <windows.h> /* for _BitScanForward */

View File

@@ -0,0 +1,12 @@
#ifndef BIO2EMU_IIDX_BI2A_H
#define BIO2EMU_IIDX_BI2A_H
#include "bio2/bi2a-iidx.h"
#include "bio2emu/emu.h"
void bio2_emu_bi2a_init(struct bio2emu_port *in, bool disable_poll_limiter);
void bio2_emu_bi2a_dispatch_request(
struct bio2emu_port *bio2port, const struct ac_io_message *req);
#endif

View File

@@ -69,7 +69,7 @@ bio2emu_port_dispatch_irp(struct irp *irp)
}
if (!selected_emu) {
return irp_invoke_next(irp);
return iohook_invoke_next(irp);
}
struct ac_io_emu *emu = &selected_emu->acio;

View File

@@ -350,8 +350,8 @@ static CONFIGRET my_CM_Get_Device_IDA(
log_info("%s: Injecting custom parent ID for BIO2", __FUNCTION__);
strcpy(Buffer, devpath);
Buffer[devpathsize - 1] =
'\0' + (dnDevInst & CUSTOM_DEVICE_INSTANCE_IDXMASK);
Buffer[devpathsize - 2] =
'0' + (dnDevInst & CUSTOM_DEVICE_INSTANCE_IDXMASK);
log_info("%s: %s", __FUNCTION__, Buffer);
return CR_SUCCESS;
}

View File

@@ -52,7 +52,7 @@ ac_io_bus_dispatch_irp(struct irp *irp)
log_assert(irp != NULL);
if (!ac_io_emu_match_irp(&ac_io_emu, irp)) {
return irp_invoke_next(irp);
return iohook_invoke_next(irp);
}
for (;;) {

View File

@@ -20,10 +20,6 @@
#include "util/defs.h"
#include "util/log.h"
static const irp_handler_t bsthook_handlers[] = {
ac_io_bus_dispatch_irp,
};
static bool my_dll_entry_init(char *sidcode, struct property_node *config);
static bool my_dll_entry_main(void);
@@ -116,7 +112,7 @@ BOOL WINAPI DllMain(HMODULE self, DWORD reason, void *ctx)
args_free(argc, argv);
app_hook_init(my_dll_entry_init, my_dll_entry_main);
iohook_init(bsthook_handlers, lengthof(bsthook_handlers));
iohook_push_handler(ac_io_bus_dispatch_irp);
rs232_hook_init();
gfx_init();

View File

@@ -41,7 +41,7 @@ static HRESULT STDCALL my_CreateDevice(
D3DPRESENT_PARAMETERS *pp,
IDirect3DDevice9 **pdev)
{
IDirect3D9 *real = COM_PROXY_UNWRAP(self);
IDirect3D9 *real = com_proxy_downcast(self)->real;
HRESULT hr;
log_misc("IDirect3D9::CreateDevice hook hit");
@@ -61,11 +61,17 @@ static IDirect3D9 *STDCALL my_Direct3DCreate9(UINT sdk_ver)
IDirect3D9 *api;
IDirect3D9Vtbl *api_vtbl;
struct com_proxy *api_proxy;
HRESULT res;
log_info("Direct3DCreate9 hook hit");
api = real_Direct3DCreate9(sdk_ver);
api_proxy = com_proxy_wrap(api, sizeof(*api->lpVtbl));
res = com_proxy_wrap(&api_proxy, api, sizeof(*api->lpVtbl));
if (res != S_OK) {
log_fatal("Wrapping com proxy failed: 0x%ld", res);
}
api_vtbl = api_proxy->vptr;
api_vtbl->CreateDevice = my_CreateDevice;

View File

@@ -341,7 +341,14 @@ static HRESULT my_MFEnumDeviceSources(
for (UINT32 i = 0; i < nsrcs; ++i) {
api = (*pppSourceActivate)[i];
api_proxy = com_proxy_wrap(api, sizeof(*api->lpVtbl));
ret = com_proxy_wrap(&api_proxy, api, sizeof(*api->lpVtbl));
if (ret != S_OK) {
log_warning("Wrapping com proxy failed: %08lx", ret);
return ret;
}
api_vtbl = api_proxy->vptr;
real_GetAllocatedString = api_vtbl->GetAllocatedString;

View File

@@ -256,13 +256,33 @@ STRINGTABLE
IDS_DDR_P2_DOWN "P2 Down"
IDS_DDR_P2_LEFT "P2 Left"
IDS_DDR_P2_RIGHT "P2 Right"
IDS_DDR_P1_MENU_LIGHT "P1 Menu Lights"
IDS_DDR_P1_MENU_LIGHT "P1 Menu Lights / HD Spot Red Satellite"
IDS_DDR_P1_TOP_LIGHT "P1 Marquee Top Light"
IDS_DDR_P1_BOTTOM_LIGHT "P1 Marquee Bottom Light"
IDS_DDR_P2_MENU_LIGHT "P2 Menu Lights"
IDS_DDR_P2_MENU_LIGHT "P2 Menu Lights / HD Spot Blue Satellite"
IDS_DDR_P2_TOP_LIGHT "P2 Marquee Top Light"
IDS_DDR_P2_BOTTOM_LIGHT "P2 Marquee Bottom Light"
IDS_DDR_BASS_LIGHT "Bass Neons"
IDS_DDR_HD_P1_START "P1 HD Start"
IDS_DDR_HD_P1_UP_DOWN "P1 HD Up/Down"
IDS_DDR_HD_P1_LEFT_RIGHT "P1 HD Left/Right"
IDS_DDR_HD_P2_START "P2 HD Start"
IDS_DDR_HD_P2_UP_DOWN "P2 HD Up/Down"
IDS_DDR_HD_P2_LEFT_RIGHT "P2 HD Left/Right"
IDS_DDR_HD_P1_SPEAKER_F_R "P1 HD Speaker F R"
IDS_DDR_HD_P1_SPEAKER_F_G "P1 HD Speaker F G"
IDS_DDR_HD_P1_SPEAKER_F_B "P1 HD Speaker F B"
IDS_DDR_HD_P2_SPEAKER_F_R "P2 HD Speaker F R"
IDS_DDR_HD_P2_SPEAKER_F_G "P2 HD Speaker F G"
IDS_DDR_HD_P2_SPEAKER_F_B "P2 HD Speaker F B"
IDS_DDR_HD_P1_SPEAKER_W_R "P1 HD Speaker W R"
IDS_DDR_HD_P1_SPEAKER_W_G "P1 HD Speaker W G"
IDS_DDR_HD_P1_SPEAKER_W_B "P1 HD Speaker W B"
IDS_DDR_HD_P2_SPEAKER_W_R "P2 HD Speaker W R"
IDS_DDR_HD_P2_SPEAKER_W_G "P2 HD Speaker W G"
IDS_DDR_HD_P2_SPEAKER_W_B "P2 HD Speaker W B"
IDS_DDR_HD_SPOT_RED_TOP "HD Spot Red Top"
IDS_DDR_HD_SPOT_BLUE_TOP "HD Spot Blue Top"
IDS_PNM_SCHEMA "pop'n music"
IDS_PNM_BTN1 "Button 1"
IDS_PNM_BTN2 "Button 2"
@@ -273,6 +293,15 @@ STRINGTABLE
IDS_PNM_BTN7 "Button 7"
IDS_PNM_BTN8 "Button 8"
IDS_PNM_BTN9 "Button 9"
IDS_PNM_TOP1 "Top neon 1 (topmost red)"
IDS_PNM_TOP2 "Top neon 2 (orange)"
IDS_PNM_TOP3 "Top neon 3 (green)"
IDS_PNM_TOP4 "Top neon 4 (green)"
IDS_PNM_TOP5 "Top neon 5 (bottom green)"
IDS_PNM_LB "Left lamp (blue)"
IDS_PNM_LR "Left lamp (red)"
IDS_PNM_RB "Right lamp (blue)"
IDS_PNM_RR "Right lamp (red)"
IDS_JB_SCHEMA "Jubeat"
IDS_JB_PANEL1 "Panel 1"
IDS_JB_PANEL2 "Panel 2"

View File

@@ -105,19 +105,32 @@ int main(int argc, char **argv)
eam_io_init(crt_thread_create, crt_thread_join, crt_thread_destroy);
eam_io_config_api = eam_io_get_config_api();
// calculate these and check against the loaded config
max_light = -1;
for (i = 0; i < schema->nlights; i++) {
if (max_light < schema->lights[i].bit) {
max_light = schema->lights[i].bit;
}
}
if (!mapper_config_load(schema->name)) {
log_info("Initializing empty config for %s", schema->name);
max_light = -1;
for (i = 0; i < schema->nlights; i++) {
if (max_light < schema->lights[i].bit) {
max_light = schema->lights[i].bit;
}
}
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));
}
if (mapper_get_nanalogs() != schema->nanalogs) {
log_info("Updating nanalogs for %s", schema->name);
mapper_set_nanalogs((uint8_t) schema->nanalogs);
}
}
memset(&psh, 0, sizeof(psh));

View File

@@ -243,3 +243,32 @@
#define IDS_IIDX_PANEL_S3 40200
#define IDS_IIDX_PANEL_S4 40201
#define IDS_IIDX_PANEL_S5 40202
#define IDS_PNM_TOP1 40203
#define IDS_PNM_TOP2 40204
#define IDS_PNM_TOP3 40205
#define IDS_PNM_TOP4 40206
#define IDS_PNM_TOP5 40207
#define IDS_PNM_LB 40208
#define IDS_PNM_LR 40209
#define IDS_PNM_RB 40210
#define IDS_PNM_RR 40211
#define IDS_DDR_HD_P1_START 40212
#define IDS_DDR_HD_P1_UP_DOWN 40213
#define IDS_DDR_HD_P1_LEFT_RIGHT 40214
#define IDS_DDR_HD_P2_START 40215
#define IDS_DDR_HD_P2_UP_DOWN 40216
#define IDS_DDR_HD_P2_LEFT_RIGHT 40217
#define IDS_DDR_HD_P1_SPEAKER_F_R 40218
#define IDS_DDR_HD_P1_SPEAKER_F_G 40219
#define IDS_DDR_HD_P1_SPEAKER_F_B 40220
#define IDS_DDR_HD_P2_SPEAKER_F_R 40221
#define IDS_DDR_HD_P2_SPEAKER_F_G 40222
#define IDS_DDR_HD_P2_SPEAKER_F_B 40223
#define IDS_DDR_HD_P1_SPEAKER_W_R 40224
#define IDS_DDR_HD_P1_SPEAKER_W_G 40225
#define IDS_DDR_HD_P1_SPEAKER_W_B 40226
#define IDS_DDR_HD_P2_SPEAKER_W_R 40227
#define IDS_DDR_HD_P2_SPEAKER_W_G 40228
#define IDS_DDR_HD_P2_SPEAKER_W_B 40229
#define IDS_DDR_HD_SPOT_RED_TOP 40230
#define IDS_DDR_HD_SPOT_BLUE_TOP 40231

View File

@@ -3,30 +3,32 @@
#include "util/defs.h"
static const struct action_def dm_actions[] = {{0x01, IDS_GENERIC_TEST},
{0x00, IDS_GENERIC_SERVICE},
static const struct action_def dm_actions[] = {
{0x01, IDS_GENERIC_TEST},
{0x00, IDS_GENERIC_SERVICE},
{0x08, IDS_DM_START},
{0x0F, IDS_DM_MENU_LEFT},
{0x11, IDS_DM_MENU_RIGHT},
{0x08, IDS_DM_START},
{0x0F, IDS_DM_MENU_LEFT},
{0x11, IDS_DM_MENU_RIGHT},
{0x0A, IDS_DM_HI_HAT},
{0x0C, IDS_DM_SNARE},
{0x0E, IDS_DM_HIGH_TOM},
{0x10, IDS_DM_LOW_TOM},
{0x12, IDS_DM_CYMBAL},
{0x16, IDS_DM_BASS}};
{0x0A, IDS_DM_HI_HAT},
{0x0C, IDS_DM_SNARE},
{0x0E, IDS_DM_HIGH_TOM},
{0x10, IDS_DM_LOW_TOM},
{0x12, IDS_DM_CYMBAL},
{0x16, IDS_DM_BASS}};
static const struct light_def dm_lights[] = {{0x00, IDS_DM_HI_HAT},
{0x01, IDS_DM_SNARE},
{0x02, IDS_DM_HIGH_TOM},
{0x03, IDS_DM_LOW_TOM},
{0x04, IDS_DM_CYMBAL},
{0x09, IDS_DM_BASS},
{0x0A, IDS_DM_SPEAKER_LIGHT},
{0x08, IDS_DM_SPOT_LIGHT},
{0x06, IDS_DM_START_LIGHT},
{0x07, IDS_DM_MENU_LIGHT}};
static const struct light_def dm_lights[] = {
{0x00, IDS_DM_HI_HAT},
{0x01, IDS_DM_SNARE},
{0x02, IDS_DM_HIGH_TOM},
{0x03, IDS_DM_LOW_TOM},
{0x04, IDS_DM_CYMBAL},
{0x09, IDS_DM_BASS},
{0x0A, IDS_DM_SPEAKER_LIGHT},
{0x08, IDS_DM_SPOT_LIGHT},
{0x06, IDS_DM_START_LIGHT},
{0x07, IDS_DM_MENU_LIGHT}};
static const struct action_def gf_actions[] = {
{0x01, IDS_GENERIC_TEST}, {0x00, IDS_GENERIC_SERVICE},
@@ -43,10 +45,11 @@ static const struct action_def gf_actions[] = {
{0x13, IDS_GF_P2_RED}, {0x15, IDS_GF_P2_GREEN},
{0x17, IDS_GF_P2_BLUE}};
static const struct light_def gf_lights[] = {{0x08, IDS_GF_P1_SPOT_LIGHT},
{0x09, IDS_GF_P2_SPOT_LIGHT},
{0x0A, IDS_GF_P1_START},
{0x0B, IDS_GF_P2_START}};
static const struct light_def gf_lights[] = {
{0x08, IDS_GF_P1_SPOT_LIGHT},
{0x09, IDS_GF_P2_SPOT_LIGHT},
{0x0A, IDS_GF_P1_START},
{0x0B, IDS_GF_P2_START}};
static const struct action_def iidx_actions[] = {
{0x1C, IDS_GENERIC_TEST}, {0x1D, IDS_GENERIC_SERVICE},
@@ -101,8 +104,8 @@ static const struct light_def iidx_lights[] = {
{0x1F, IDS_IIDX_NEON_LIGHT}};
static const struct analog_def iidx_analogs[] = {{0, IDS_IIDX_P1_TT},
{1, IDS_IIDX_P2_TT}};
static const struct analog_def iidx_analogs[] = {
{0, IDS_IIDX_P1_TT}, {1, IDS_IIDX_P2_TT}};
static const struct action_def ddr_actions[] = {
{0x04, IDS_GENERIC_TEST}, {0x06, IDS_GENERIC_SERVICE},
@@ -122,19 +125,47 @@ static const struct action_def ddr_actions[] = {
static const struct light_def ddr_lights[] = {
/* These are split between non-overlapping P3IO and EXTIO state words */
// P3IO: SD
{0x00, IDS_DDR_P1_MENU_LIGHT},
{0x07, IDS_DDR_P1_TOP_LIGHT},
{0x07, IDS_DDR_P1_BOTTOM_LIGHT},
{0x1E, IDS_DDR_P1_UP},
{0x1D, IDS_DDR_P1_DOWN},
{0x1C, IDS_DDR_P1_LEFT},
{0x1B, IDS_DDR_P1_RIGHT},
{0x06, IDS_DDR_P1_BOTTOM_LIGHT},
{0x01, IDS_DDR_P2_MENU_LIGHT},
{0x05, IDS_DDR_P2_TOP_LIGHT},
{0x04, IDS_DDR_P2_BOTTOM_LIGHT},
// P3IO: HD
{0x02, IDS_DDR_HD_SPOT_RED_TOP},
{0x03, IDS_DDR_HD_SPOT_BLUE_TOP},
// P3IO: HDXS
{0x08, IDS_DDR_HD_P1_START},
{0x09, IDS_DDR_HD_P1_UP_DOWN},
{0x0A, IDS_DDR_HD_P1_LEFT_RIGHT},
{0x0B, IDS_DDR_HD_P2_START},
{0x0C, IDS_DDR_HD_P2_UP_DOWN},
{0x0D, IDS_DDR_HD_P2_LEFT_RIGHT},
{0x20, IDS_DDR_HD_P1_SPEAKER_F_R},
{0x21, IDS_DDR_HD_P1_SPEAKER_F_G},
{0x22, IDS_DDR_HD_P1_SPEAKER_F_B},
{0x23, IDS_DDR_HD_P2_SPEAKER_F_R},
{0x24, IDS_DDR_HD_P2_SPEAKER_F_G},
{0x25, IDS_DDR_HD_P2_SPEAKER_F_B},
{0x26, IDS_DDR_HD_P1_SPEAKER_W_R},
{0x27, IDS_DDR_HD_P1_SPEAKER_W_G},
{0x28, IDS_DDR_HD_P1_SPEAKER_W_B},
{0x29, IDS_DDR_HD_P2_SPEAKER_W_R},
{0x2A, IDS_DDR_HD_P2_SPEAKER_W_G},
{0x2B, IDS_DDR_HD_P2_SPEAKER_W_B},
// EXTIO
{0x1E, IDS_DDR_P1_UP},
{0x1D, IDS_DDR_P1_DOWN},
{0x1C, IDS_DDR_P1_LEFT},
{0x1B, IDS_DDR_P1_RIGHT},
{0x16, IDS_DDR_P2_UP},
{0x15, IDS_DDR_P2_DOWN},
{0x14, IDS_DDR_P2_LEFT},
@@ -142,18 +173,19 @@ static const struct light_def ddr_lights[] = {
{0x0E, IDS_DDR_BASS_LIGHT}};
static const struct action_def pnm_actions[] = {{0x07, IDS_GENERIC_TEST},
{0x06, IDS_GENERIC_SERVICE},
static const struct action_def pnm_actions[] = {
{0x07, IDS_GENERIC_TEST},
{0x06, IDS_GENERIC_SERVICE},
{0x08, IDS_PNM_BTN1},
{0x09, IDS_PNM_BTN2},
{0x0A, IDS_PNM_BTN3},
{0x0B, IDS_PNM_BTN4},
{0x0C, IDS_PNM_BTN5},
{0x0D, IDS_PNM_BTN6},
{0x0E, IDS_PNM_BTN7},
{0x0F, IDS_PNM_BTN8},
{0x10, IDS_PNM_BTN9}};
{0x08, IDS_PNM_BTN1},
{0x09, IDS_PNM_BTN2},
{0x0A, IDS_PNM_BTN3},
{0x0B, IDS_PNM_BTN4},
{0x0C, IDS_PNM_BTN5},
{0x0D, IDS_PNM_BTN6},
{0x0E, IDS_PNM_BTN7},
{0x0F, IDS_PNM_BTN8},
{0x10, IDS_PNM_BTN9}};
static const struct light_def pnm_lights[] = {
{0x17, IDS_PNM_BTN1},
@@ -165,27 +197,37 @@ static const struct light_def pnm_lights[] = {
{0x1D, IDS_PNM_BTN7},
{0x1E, IDS_PNM_BTN8},
{0x1F, IDS_PNM_BTN9},
{0x20, IDS_PNM_TOP1},
{0x21, IDS_PNM_TOP2},
{0x22, IDS_PNM_TOP3},
{0x23, IDS_PNM_TOP4},
{0x24, IDS_PNM_TOP5},
{0x25, IDS_PNM_LB},
{0x26, IDS_PNM_LR},
{0x27, IDS_PNM_RB},
{0x28, IDS_PNM_RR},
};
static const struct action_def jb_actions[] = {{0x10, IDS_GENERIC_TEST},
{0x11, IDS_GENERIC_SERVICE},
static const struct action_def jb_actions[] = {
{0x10, IDS_GENERIC_TEST},
{0x11, IDS_GENERIC_SERVICE},
{0x00, IDS_JB_PANEL1},
{0x01, IDS_JB_PANEL2},
{0x02, IDS_JB_PANEL3},
{0x03, IDS_JB_PANEL4},
{0x04, IDS_JB_PANEL5},
{0x05, IDS_JB_PANEL6},
{0x06, IDS_JB_PANEL7},
{0x07, IDS_JB_PANEL8},
{0x08, IDS_JB_PANEL9},
{0x09, IDS_JB_PANEL10},
{0x0A, IDS_JB_PANEL11},
{0x0B, IDS_JB_PANEL12},
{0x0C, IDS_JB_PANEL13},
{0x0D, IDS_JB_PANEL14},
{0x0E, IDS_JB_PANEL15},
{0x0F, IDS_JB_PANEL16}};
{0x00, IDS_JB_PANEL1},
{0x01, IDS_JB_PANEL2},
{0x02, IDS_JB_PANEL3},
{0x03, IDS_JB_PANEL4},
{0x04, IDS_JB_PANEL5},
{0x05, IDS_JB_PANEL6},
{0x06, IDS_JB_PANEL7},
{0x07, IDS_JB_PANEL8},
{0x08, IDS_JB_PANEL9},
{0x09, IDS_JB_PANEL10},
{0x0A, IDS_JB_PANEL11},
{0x0B, IDS_JB_PANEL12},
{0x0C, IDS_JB_PANEL13},
{0x0D, IDS_JB_PANEL14},
{0x0E, IDS_JB_PANEL15},
{0x0F, IDS_JB_PANEL16}};
static const struct light_def jb_lights[] = {
{0x00, IDS_JB_RGB_FRONT_R},
@@ -208,15 +250,16 @@ static const struct light_def jb_lights[] = {
{0x11, IDS_JB_RGB_WOOFER_B},
};
static const struct action_def sdvx_actions[] = {{0x05, IDS_GENERIC_TEST},
{0x04, IDS_GENERIC_SERVICE},
{0x0B, IDS_SDVX_START},
{0x0A, IDS_SDVX_BTN_A},
{0x09, IDS_SDVX_BTN_B},
{0x08, IDS_SDVX_BTN_C},
{0x15, IDS_SDVX_BTN_D},
{0x14, IDS_SDVX_FX_L},
{0x13, IDS_SDVX_FX_R}};
static const struct action_def sdvx_actions[] = {
{0x05, IDS_GENERIC_TEST},
{0x04, IDS_GENERIC_SERVICE},
{0x0B, IDS_SDVX_START},
{0x0A, IDS_SDVX_BTN_A},
{0x09, IDS_SDVX_BTN_B},
{0x08, IDS_SDVX_BTN_C},
{0x15, IDS_SDVX_BTN_D},
{0x14, IDS_SDVX_FX_L},
{0x13, IDS_SDVX_FX_R}};
static const struct light_def sdvx_lights[] = {
{0x0D, IDS_SDVX_BTN_A}, {0x0E, IDS_SDVX_BTN_B}, {0x0F, IDS_SDVX_BTN_C},
@@ -229,19 +272,19 @@ static const struct light_def sdvx_lights[] = {
{0x1E, IDS_SDVX_RGB5_B}, {0x1F, IDS_SDVX_RGB6_R}, {0x20, IDS_SDVX_RGB6_G},
{0x21, IDS_SDVX_RGB6_B}};
static const struct analog_def sdvx_analogs[] = {{0, IDS_SDVX_VOL_L},
{1, IDS_SDVX_VOL_R}};
static const struct analog_def sdvx_analogs[] = {
{0, IDS_SDVX_VOL_L}, {1, IDS_SDVX_VOL_R}};
static const struct action_def rb_actions[] = {{0x00, IDS_GENERIC_TEST},
{0x01, IDS_GENERIC_SERVICE}};
static const struct action_def rb_actions[] = {
{0x00, IDS_GENERIC_TEST}, {0x01, IDS_GENERIC_SERVICE}};
static const struct action_def bst_actions[] = {
{0x05, IDS_GENERIC_TEST},
{0x04, IDS_GENERIC_SERVICE},
};
static const struct eam_unit_def schema_eam_unit_defs[] = {{IDS_READER_P1, 0},
{IDS_READER_P2, 1}};
static const struct eam_unit_def schema_eam_unit_defs[] = {
{IDS_READER_P1, 0}, {IDS_READER_P2, 1}};
const struct schema schemas[] = {
{"iidx",

View File

@@ -10,6 +10,7 @@
#define D3D9EXHOOK_CONFIG_GFX_FRAMED_KEY "gfx.framed"
#define D3D9EXHOOK_CONFIG_GFX_WINDOWED_KEY "gfx.windowed"
#define D3D9EXHOOK_CONFIG_GFX_CONFINED_KEY "gfx.confined"
#define D3D9EXHOOK_CONFIG_GFX_WINDOW_WIDTH_KEY "gfx.window_width"
#define D3D9EXHOOK_CONFIG_GFX_WINDOW_HEIGHT_KEY "gfx.window_height"
#define D3D9EXHOOK_CONFIG_GFX_FORCED_REFRESHRATE_KEY "gfx.forced_refresh_rate"
@@ -18,6 +19,7 @@
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_FRAMED_VALUE false
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOWED_VALUE false
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_CONFINED_VALUE false
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_WIDTH_VALUE -1
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_HEIGHT_VALUE -1
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_FORCED_RR_VALUE -1
@@ -38,6 +40,12 @@ void d3d9exhook_config_gfx_init(struct cconfig *config)
D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOWED_VALUE,
"Run the game windowed");
cconfig_util_set_bool(
config,
D3D9EXHOOK_CONFIG_GFX_CONFINED_KEY,
D3D9EXHOOK_CONFIG_GFX_DEFAULT_CONFINED_VALUE,
"Confine mouse coursor to window");
cconfig_util_set_int(
config,
D3D9EXHOOK_CONFIG_GFX_WINDOW_WIDTH_KEY,
@@ -99,6 +107,18 @@ void d3d9exhook_config_gfx_get(
D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOWED_VALUE);
}
if (!cconfig_util_get_bool(
config,
D3D9EXHOOK_CONFIG_GFX_CONFINED_KEY,
&config_gfx->confined,
D3D9EXHOOK_CONFIG_GFX_DEFAULT_CONFINED_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%d'",
D3D9EXHOOK_CONFIG_GFX_CONFINED_KEY,
D3D9EXHOOK_CONFIG_GFX_DEFAULT_CONFINED_VALUE);
}
if (!cconfig_util_get_int(
config,
D3D9EXHOOK_CONFIG_GFX_WINDOW_WIDTH_KEY,

View File

@@ -12,6 +12,7 @@
struct d3d9exhook_config_gfx {
bool framed;
bool windowed;
bool confined;
int32_t window_width;
int32_t window_height;
int32_t forced_refresh_rate;

View File

@@ -47,6 +47,8 @@ static HRESULT STDCALL my_CreateDeviceEx(
static HRESULT STDCALL my_Direct3DCreate9Ex(UINT sdk_ver, IDirect3D9Ex **api);
static WNDPROC real_WndProc;
static BOOL STDCALL my_EnumDisplayDevicesA(
const char *dev_name, DWORD dev_num, DISPLAY_DEVICEA *info, DWORD flags);
@@ -82,6 +84,7 @@ static BOOL(STDCALL *real_MoveWindow)(
/* ------------------------------------------------------------------------- */
static bool d3d9ex_windowed;
static bool d3d9ex_confined;
static int32_t d3d9ex_force_refresh_rate = -1;
static int32_t d3d9ex_window_width = -1;
static int32_t d3d9ex_window_height = -1;
@@ -183,6 +186,52 @@ my_MoveWindow(HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint)
return result;
}
static LRESULT gfx_confine(HWND hwnd)
{
POINT p;
RECT r;
log_misc("Confining mouse (ALT-TAB to release)");
p.x = 0;
p.y = 0;
ClientToScreen(hwnd, &p);
r.left = p.x;
r.top = p.y;
r.right = p.x + 100;
r.bottom = p.y + 100;
ClipCursor(&r);
return TRUE;
}
static LRESULT gfx_unconfine(HWND hwnd)
{
log_misc("Un-confining mouse");
ClipCursor(NULL);
return TRUE;
}
static LRESULT CALLBACK
my_WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg) {
case WM_SETFOCUS:
return gfx_confine(hwnd);
case WM_KILLFOCUS:
return gfx_unconfine(hwnd);
default:
return CallWindowProc(real_WndProc, hwnd, msg, wparam, lparam);
}
}
static HRESULT STDCALL my_CreateDeviceEx(
IDirect3D9Ex *self,
UINT adapter,
@@ -193,7 +242,7 @@ static HRESULT STDCALL my_CreateDeviceEx(
D3DDISPLAYMODEEX *fdm,
IDirect3DDevice9Ex **pdev)
{
IDirect3D9Ex *real = COM_PROXY_UNWRAP(self);
IDirect3D9Ex *real = com_proxy_downcast(self)->real;
HRESULT hr;
if (d3d9ex_device_adapter >= 0) {
@@ -268,6 +317,12 @@ static HRESULT STDCALL my_CreateDeviceEx(
hr = IDirect3D9Ex_CreateDeviceEx(
real, adapter, type, hwnd, flags, pp, fdm, pdev);
if (SUCCEEDED(hr) && d3d9ex_confined) {
real_WndProc = (void *) GetWindowLongPtr(hwnd, GWLP_WNDPROC);
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (uintptr_t) my_WndProc);
}
return hr;
}
@@ -282,7 +337,14 @@ static HRESULT STDCALL my_Direct3DCreate9Ex(UINT sdk_ver, IDirect3D9Ex **api)
hr = real_Direct3DCreate9Ex(sdk_ver, api);
api_ = *api;
api_proxy = com_proxy_wrap(api_, sizeof(*api_->lpVtbl));
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;
@@ -319,6 +381,7 @@ void d3d9ex_hook_init(void)
void d3d9ex_configure(struct d3d9exhook_config_gfx *gfx_config)
{
d3d9ex_windowed = gfx_config->windowed;
d3d9ex_confined = gfx_config->confined;
d3d9ex_window_framed = gfx_config->framed;
d3d9ex_window_width = gfx_config->window_width;
d3d9ex_window_height = gfx_config->window_height;

View File

@@ -9,7 +9,6 @@ libs_ddrhook := \
p3io \
hook \
hooklib \
security \
util \
eamio \
ddrio \

View File

@@ -11,10 +11,14 @@
#include <string.h>
#include <wchar.h>
#include "acio/hdxs.h"
#include "acioemu/addr.h"
#include "acioemu/hdxs.h"
#include "acioemu/icca.h"
#include "bemanitools/ddrio.h"
#include "ddrhook/_com4.h"
#include "hook/iohook.h"
@@ -29,16 +33,60 @@ static struct ac_io_emu com4_ac_io_emu;
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)
{
if (output->lights[panel_idx].bit) {
return 1 << out_idx;
} else {
return 0;
}
}
static uint8_t upscale_light(uint8_t in_7bit) {
if (in_7bit < 0x10) {
return in_7bit * 2;
} else {
// so we can actually reach 0xFF
return (in_7bit * 2) + 1;
}
}
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);
ddr_io_set_lights_hdxs_panel(lights);
for (uint8_t i = 0; i < 4; ++i) {
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);
ddr_io_set_lights_hdxs_rgb(i, r, g, b);
}
}
void com4_init(void)
{
uint8_t i;
/* This isn't a real COM port, we configure the core P3IO emulator code to
generate IRPs addressed to COM4 and then we intercept them. */
p3io_uart_set_path(0, L"COM4");
ac_io_emu_init(&com4_ac_io_emu, L"COM4");
ac_io_emu_hdxs_init(&com4_hdxs, &com4_ac_io_emu);
ac_io_emu_hdxs_init(&com4_hdxs, &com4_ac_io_emu, lights_dispatcher);
for (i = 0; i < lengthof(com4_icca); i++) {
ac_io_emu_icca_init(&com4_icca[i], &com4_ac_io_emu, i);
@@ -59,7 +107,7 @@ com4_dispatch_irp(struct irp *irp)
log_assert(irp != NULL);
if (!ac_io_emu_match_irp(&com4_ac_io_emu, irp)) {
return irp_invoke_next(irp);
return iohook_invoke_next(irp);
}
for (;;) {

View File

@@ -72,10 +72,18 @@ static HRESULT STDCALL my_DirectInput8Create(
res = real_DirectInput8Create(
hinst, dwVersion, riidltf, (LPVOID *) &api, punkOuter);
if (res != DI_OK) {
return res;
}
api_proxy = com_proxy_wrap(api, sizeof(*api->lpVtbl));
res = com_proxy_wrap(&api_proxy, api, sizeof(*api->lpVtbl));
if (res != S_OK) {
log_warning("Wrapping com proxy failed: %08lx", res);
return res;
}
api_vtbl = api_proxy->vptr;
api_vtbl->EnumDevices = my_EnumDevices;

View File

@@ -32,23 +32,17 @@ static bool my_dll_entry_main(void);
bool standard_def;
bool _15khz;
static const irp_handler_t ddrhook_handlers[] = {
p3io_emu_dispatch_irp,
extio_dispatch_irp,
spike_dispatch_irp,
usbmem_dispatch_irp,
com4_dispatch_irp,
};
static bool my_dll_entry_init(char *sidcode, struct property_node *param)
{
int argc;
char **argv;
bool com4;
bool ok;
int i;
log_info("--- Begin ddrhook dll_entry_init ---");
com4 = true;
args_recover(&argc, &argv);
for (i = 1; i < argc; i++) {
@@ -65,13 +59,29 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param)
case 'w':
gfx_set_windowed();
break;
case 'u':
/* Don't emulate P3IO COM4 and its downstream devices, use the
Windows COM4 port instead. */
com4 = false;
break;
}
}
args_free(argc, argv);
iohook_init(ddrhook_handlers, lengthof(ddrhook_handlers));
iohook_push_handler(p3io_emu_dispatch_irp);
iohook_push_handler(extio_dispatch_irp);
iohook_push_handler(spike_dispatch_irp);
iohook_push_handler(usbmem_dispatch_irp);
if (com4) {
/* See ddrhook/p3io.c for details. */
iohook_push_handler(com4_dispatch_irp);
}
rs232_hook_init();
master_insert_hooks(NULL);
@@ -92,15 +102,17 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param)
return false;
}
log_info("Initializing card reader backend");
if (com4) {
log_info("Initializing card reader backend");
eam_io_set_loggers(
log_body_misc, log_body_info, log_body_warning, log_body_fatal);
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;
if (!ok) {
return false;
}
}
log_info("--- End ddrhook dll_entry_init ---");

View File

@@ -33,7 +33,13 @@ void extio_init(void)
{
log_assert(extio_fd == NULL);
extio_fd = iohook_open_dummy_fd();
HRESULT hr;
hr = iohook_open_nul_fd(&extio_fd);
if (hr != S_OK) {
log_fatal("Opening nul fd failed: %08lx", hr);
}
}
void extio_fini(void)
@@ -51,7 +57,7 @@ extio_dispatch_irp(struct irp *irp)
log_assert(irp != NULL);
if (irp->op != IRP_OP_OPEN && irp->fd != extio_fd) {
return irp_invoke_next(irp);
return iohook_invoke_next(irp);
}
switch (irp->op) {
@@ -75,7 +81,7 @@ static HRESULT extio_open(struct irp *irp)
log_assert(irp != NULL);
if (!wstr_eq(irp->open_filename, L"COM1")) {
return irp_invoke_next(irp);
return iohook_invoke_next(irp);
}
log_info("EXTIO RS232 port opened");

View File

@@ -43,7 +43,7 @@ static HRESULT STDCALL my_CreateDevice(
{
IDirect3D9 *real;
real = COM_PROXY_UNWRAP(self);
real = com_proxy_downcast(self)->real;
if (gfx_windowed) {
pp->Windowed = TRUE;
@@ -58,11 +58,18 @@ static IDirect3D9 *STDCALL my_Direct3DCreate9(UINT sdk_ver)
IDirect3D9 *api;
IDirect3D9Vtbl *api_vtbl;
struct com_proxy *api_proxy;
HRESULT hr;
log_info("Direct3DCreate9 hook hit");
api = real_Direct3DCreate9(sdk_ver);
api_proxy = com_proxy_wrap(api, sizeof(*api->lpVtbl));
hr = com_proxy_wrap(&api_proxy, api, sizeof(*api->lpVtbl));
if (hr != S_OK) {
log_fatal("Wrapping com proxy failed: %08lx", hr);
}
api_vtbl = api_proxy->vptr;
api_vtbl->CreateDevice = my_CreateDevice;

View File

@@ -29,6 +29,12 @@ static const struct p3io_ops p3io_ddr_ops = {
void p3io_ddr_init(void)
{
/* 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
_com4.c (or possibly don't, in which case the communications will be
sent to the real COM4 on your system) */
p3io_uart_set_path(0, L"COM4");
p3io_emu_init(&p3io_ddr_ops, NULL);
}

View File

@@ -47,7 +47,7 @@ spike_dispatch_irp(struct irp *irp)
log_assert(irp != NULL);
if (!ac_io_emu_match_irp(&spike_ac_io_emu, irp)) {
return irp_invoke_next(irp);
return iohook_invoke_next(irp);
}
for (;;) {

View File

@@ -34,7 +34,13 @@ void usbmem_init(void)
{
log_assert(usbmem_fd == NULL);
usbmem_fd = iohook_open_dummy_fd();
HRESULT hr;
hr = iohook_open_nul_fd(&usbmem_fd);
if (hr != S_OK) {
log_fatal("Opening nul fd failed: %08lx", hr);
}
}
void usbmem_fini(void)
@@ -52,7 +58,7 @@ usbmem_dispatch_irp(struct irp *irp)
log_assert(irp != NULL);
if (irp->op != IRP_OP_OPEN && irp->fd != usbmem_fd) {
return irp_invoke_next(irp);
return iohook_invoke_next(irp);
}
switch (irp->op) {
@@ -76,7 +82,7 @@ static HRESULT usbmem_open(struct irp *irp)
log_assert(irp != NULL);
if (!wstr_eq(irp->open_filename, L"COM3")) {
return irp_invoke_next(irp);
return iohook_invoke_next(irp);
}
irp->fd = usbmem_fd;

View File

@@ -7,3 +7,5 @@ EXPORTS
ddr_io_read_pad
ddr_io_set_lights_extio
ddr_io_set_lights_p3io
ddr_io_set_lights_hdxs_panel
ddr_io_set_lights_hdxs_rgb

View File

@@ -207,6 +207,21 @@ void ddr_io_set_lights_p3io(uint32_t p3io_lights)
atomic_fetch_and(&out.lights, ~clr);
}
void ddr_io_set_lights_hdxs_panel(uint32_t lights)
{
(void) lights;
// stubbed
}
void ddr_io_set_lights_hdxs_rgb(uint8_t idx, uint8_t r, uint8_t g, uint8_t b)
{
(void) idx;
(void) r;
(void) g;
(void) b;
// stubbed
}
void ddr_io_fini(void)
{
if (initted) {

View File

@@ -7,3 +7,5 @@ EXPORTS
ddr_io_read_pad
ddr_io_set_lights_extio
ddr_io_set_lights_p3io
ddr_io_set_lights_hdxs_panel
ddr_io_set_lights_hdxs_rgb

View File

@@ -41,24 +41,28 @@ static const struct ddr_io_smx_pad_map ddr_io_smx_pad_map[] = {
{1, 1 << 7, 1 << DDR_P2_DOWN},
};
#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
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, 48 * 1, 0xFF, 0x00, 0x00},
{1 << LIGHT_P1_LEFT, 48 * 3, 0x00, 0x00, 0xFF},
{1 << LIGHT_P1_RIGHT, 48 * 5, 0x00, 0x00, 0xFF},
{1 << LIGHT_P1_DOWN, 48 * 7, 0xFF, 0x00, 0x00},
{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_P2_UP, 48 * 10, 0xFF, 0x00, 0x00},
{1 << LIGHT_P2_LEFT, 48 * 12, 0x00, 0x00, 0xFF},
{1 << LIGHT_P2_RIGHT, 48 * 14, 0x00, 0x00, 0xFF},
{1 << LIGHT_P2_DOWN, 48 * 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];
static CRITICAL_SECTION ddr_io_smx_lights_lock;
static uint8_t ddr_io_smx_lights_counter;
static char ddr_io_smx_lights[864];
static char ddr_io_smx_lights[DDR_IO_SMX_TOTAL_LIGHT_VALUES];
void ddr_io_set_loggers(
log_formatter_t misc,
@@ -109,7 +113,7 @@ uint32_t ddr_io_read_pad(void)
EnterCriticalSection(&ddr_io_smx_lights_lock);
if (ddr_io_smx_lights_counter == 0) {
SMX_SetLights(ddr_io_smx_lights);
SMX_SetLights2(ddr_io_smx_lights, lengthof(ddr_io_smx_lights));
}
ddr_io_smx_lights_counter++;
@@ -149,7 +153,7 @@ void ddr_io_set_lights_extio(uint32_t lights)
if (lights & map->extio_bit) {
offset = map->smx_light_offset;
for (j = 0; j < 48; j += 3) {
for (j = 0; j < DDR_IO_SMX_LIGHT_VALUES_PER_PANEL; j += 3) {
ddr_io_smx_lights[offset + j] = map->r;
ddr_io_smx_lights[offset + j + 1] = map->g;
ddr_io_smx_lights[offset + j + 2] = map->b;
@@ -164,11 +168,30 @@ void ddr_io_set_lights_p3io(uint32_t lights)
{
uint8_t i;
for (i = 0x0E; i <= 0x1E; i++) {
for (i = 0x00; i <= 0x07; i++) {
mapper_write_light(i, lights & (1 << i) ? 255 : 0);
}
}
void ddr_io_set_lights_hdxs_panel(uint32_t lights)
{
uint8_t i;
for (i = 0x08; i <= 0x0D; i++) {
mapper_write_light(i, lights & (1 << i) ? 255 : 0);
}
}
void ddr_io_set_lights_hdxs_rgb(uint8_t idx, uint8_t r, uint8_t g, uint8_t b)
{
if (idx < 4) {
uint8_t base = 0x20 + idx * 3;
mapper_write_light(base + 0, r);
mapper_write_light(base + 1, g);
mapper_write_light(base + 2, b);
}
}
void ddr_io_fini(void)
{
log_info("Stopping SMX.DLL");

View File

@@ -43,7 +43,7 @@ void ddr_io_set_lights_extio(uint32_t lights)
{
uint8_t i;
for (i = 0x00; i <= 0x07; i++) {
for (i = 0x0E; i <= 0x1E; i++) {
mapper_write_light(i, lights & (1 << i) ? 255 : 0);
}
}
@@ -52,11 +52,30 @@ void ddr_io_set_lights_p3io(uint32_t lights)
{
uint8_t i;
for (i = 0x0E; i <= 0x1E; i++) {
for (i = 0x00; i <= 0x07; i++) {
mapper_write_light(i, lights & (1 << i) ? 255 : 0);
}
}
void ddr_io_set_lights_hdxs_panel(uint32_t lights)
{
uint8_t i;
for (i = 0x08; i <= 0x0D; i++) {
mapper_write_light(i, lights & (1 << i) ? 255 : 0);
}
}
void ddr_io_set_lights_hdxs_rgb(uint8_t idx, uint8_t r, uint8_t g, uint8_t b)
{
if (idx < 4) {
uint8_t base = 0x20 + idx * 3;
mapper_write_light(base + 0, r);
mapper_write_light(base + 1, g);
mapper_write_light(base + 2, b);
}
}
void ddr_io_fini(void)
{
input_fini();

View File

@@ -7,3 +7,5 @@ EXPORTS
ddr_io_read_pad
ddr_io_set_lights_extio
ddr_io_set_lights_p3io
ddr_io_set_lights_hdxs_panel
ddr_io_set_lights_hdxs_rgb

10
src/main/dinput/Module.mk Normal file
View File

@@ -0,0 +1,10 @@
libs += dinput
libs_dinput := \
hook \
hooklib \
util \
src_dinput := \
dinput.c \
device_dinput8.c \

View File

@@ -0,0 +1,307 @@
#include "dinput/device_dinput8.h"
static ULONG REF_COUNT = 0;
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_QueryInterface(
IDirectInputDevice8W FAR *This, REFIID riid, void **ppvObj)
{
if (ppvObj == NULL) {
return E_POINTER;
}
if (IsEqualGUID(riid, &IID_IUnknown) ||
IsEqualGUID(riid, &IID_IDirectInputDeviceA) ||
IsEqualGUID(riid, &IID_IDirectInputDeviceW) ||
IsEqualGUID(riid, &IID_IDirectInputDevice2A) ||
IsEqualGUID(riid, &IID_IDirectInputDevice2W) ||
IsEqualGUID(riid, &IID_IDirectInputDevice7A) ||
IsEqualGUID(riid, &IID_IDirectInputDevice7W) ||
IsEqualGUID(riid, &IID_IDirectInputDevice8A) ||
IsEqualGUID(riid, &IID_IDirectInputDevice8W)) {
This->lpVtbl->AddRef(This);
*ppvObj = This;
return S_OK;
}
return E_NOINTERFACE;
}
static ULONG STDMETHODCALLTYPE
IDirectInputDevice8W_AddRef(IDirectInputDevice8W FAR *This)
{
return ++REF_COUNT;
}
static ULONG STDMETHODCALLTYPE
IDirectInputDevice8W_Release(IDirectInputDevice8W FAR *This)
{
return --REF_COUNT;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_GetCapabilities(
IDirectInputDevice8W FAR *This, LPDIDEVCAPS lpDIDevCaps)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_EnumObjects(
IDirectInputDevice8W FAR *This,
LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback,
LPVOID pvRef,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_GetProperty(
IDirectInputDevice8W FAR *This, REFGUID rguidProp, LPDIPROPHEADER pdiph)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_SetProperty(
IDirectInputDevice8W FAR *This, REFGUID rguidProp, LPCDIPROPHEADER pdiph)
{
return DI_OK;
}
static HRESULT STDMETHODCALLTYPE
IDirectInputDevice8W_Acquire(IDirectInputDevice8W FAR *This)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE
IDirectInputDevice8W_Unacquire(IDirectInputDevice8W FAR *This)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_GetDeviceState(
IDirectInputDevice8W FAR *This, DWORD cbData, LPVOID lpvData)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_GetDeviceData(
IDirectInputDevice8W FAR *This,
DWORD cbObjectData,
LPDIDEVICEOBJECTDATA rgdod,
LPDWORD pdwInOut,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_SetDataFormat(
IDirectInputDevice8W FAR *This, LPCDIDATAFORMAT lpdf)
{
return DI_OK;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_SetEventNotification(
IDirectInputDevice8W FAR *This, HANDLE hEvent)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_SetCooperativeLevel(
IDirectInputDevice8W FAR *This, HWND hWnd, DWORD dwFlags)
{
return DI_OK;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_GetObjectInfo(
IDirectInputDevice8W FAR *This,
LPDIDEVICEOBJECTINSTANCEW pdidoi,
DWORD dwObj,
DWORD dwHow)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_GetDeviceInfo(
IDirectInputDevice8W FAR *This, LPDIDEVICEINSTANCEW pdidi)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_RunControlPanel(
IDirectInputDevice8W FAR *This, HWND hwndOwner, DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_Initialize(
IDirectInputDevice8W FAR *This,
HINSTANCE hinst,
DWORD dwVersion,
REFGUID rguid)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_CreateEffect(
IDirectInputDevice8W FAR *This,
REFGUID rguid,
LPCDIEFFECT lpeff,
LPDIRECTINPUTEFFECT *ppdeff,
LPUNKNOWN punkOuter)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_EnumEffects(
IDirectInputDevice8W FAR *This,
LPDIENUMEFFECTSCALLBACKW lpCallback,
LPVOID pvRef,
DWORD dwEffType)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_GetEffectInfo(
IDirectInputDevice8W FAR *This, LPDIEFFECTINFOW pdei, REFGUID rguid)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_GetForceFeedbackState(
IDirectInputDevice8W FAR *This, LPDWORD pdwOut)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_SendForceFeedbackCommand(
IDirectInputDevice8W FAR *This, DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_EnumCreatedEffectObjects(
IDirectInputDevice8W FAR *This,
LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
LPVOID pvRef,
DWORD fl)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE
IDirectInputDevice8W_Escape(IDirectInputDevice8W FAR *This, LPDIEFFESCAPE pesc)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE
IDirectInputDevice8W_Poll(IDirectInputDevice8W FAR *This)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_SendDeviceData(
IDirectInputDevice8W FAR *This,
DWORD cbObjectData,
LPCDIDEVICEOBJECTDATA rgdod,
LPDWORD pdwInOut,
DWORD fl)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_EnumEffectsInFile(
IDirectInputDevice8W FAR *This,
LPCWSTR lpszFileName,
LPDIENUMEFFECTSINFILECALLBACK pec,
LPVOID pvRef,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_WriteEffectToFile(
IDirectInputDevice8W FAR *This,
LPCWSTR lpszFileName,
DWORD dwEntries,
LPDIFILEEFFECT rgDiFileEft,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_BuildActionMap(
IDirectInputDevice8W FAR *This,
LPDIACTIONFORMATW lpdiaf,
LPCWSTR lpszUserName,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_SetActionMap(
IDirectInputDevice8W FAR *This,
LPDIACTIONFORMATW lpdiaf,
LPCWSTR lpszUserName,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_GetImageInfo(
IDirectInputDevice8W FAR *This,
LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader)
{
return DIERR_INVALIDPARAM;
}
static IDirectInputDevice8WVtbl stub_device_vtbl = {
// IUnknown
.QueryInterface = IDirectInputDevice8W_QueryInterface,
.AddRef = IDirectInputDevice8W_AddRef,
.Release = IDirectInputDevice8W_Release,
// IDirectInputDeviceW
.GetCapabilities = IDirectInputDevice8W_GetCapabilities,
.EnumObjects = IDirectInputDevice8W_EnumObjects,
.GetProperty = IDirectInputDevice8W_GetProperty,
.SetProperty = IDirectInputDevice8W_SetProperty,
.Acquire = IDirectInputDevice8W_Acquire,
.Unacquire = IDirectInputDevice8W_Unacquire,
.GetDeviceState = IDirectInputDevice8W_GetDeviceState,
.GetDeviceData = IDirectInputDevice8W_GetDeviceData,
.SetDataFormat = IDirectInputDevice8W_SetDataFormat,
.SetEventNotification = IDirectInputDevice8W_SetEventNotification,
.SetCooperativeLevel = IDirectInputDevice8W_SetCooperativeLevel,
.GetObjectInfo = IDirectInputDevice8W_GetObjectInfo,
.GetDeviceInfo = IDirectInputDevice8W_GetDeviceInfo,
.RunControlPanel = IDirectInputDevice8W_RunControlPanel,
.Initialize = IDirectInputDevice8W_Initialize,
// IDirectInputDevice2W
.CreateEffect = IDirectInputDevice8W_CreateEffect,
.EnumEffects = IDirectInputDevice8W_EnumEffects,
.GetEffectInfo = IDirectInputDevice8W_GetEffectInfo,
.GetForceFeedbackState = IDirectInputDevice8W_GetForceFeedbackState,
.SendForceFeedbackCommand = IDirectInputDevice8W_SendForceFeedbackCommand,
.EnumCreatedEffectObjects = IDirectInputDevice8W_EnumCreatedEffectObjects,
.Escape = IDirectInputDevice8W_Escape,
.Poll = IDirectInputDevice8W_Poll,
.SendDeviceData = IDirectInputDevice8W_SendDeviceData,
// IDirectInputDevice7W
.EnumEffectsInFile = IDirectInputDevice8W_EnumEffectsInFile,
.WriteEffectToFile = IDirectInputDevice8W_WriteEffectToFile,
// IDirectInputDevice8W
.BuildActionMap = IDirectInputDevice8W_BuildActionMap,
.SetActionMap = IDirectInputDevice8W_SetActionMap,
.GetImageInfo = IDirectInputDevice8W_GetImageInfo,
};
static IDirectInputDevice8W stub_device_object = {
.lpVtbl = &stub_device_vtbl,
};
IDirectInputDevice8W *di8_stub_device = &stub_device_object;

View File

@@ -0,0 +1,10 @@
#ifndef DINPUTHOOK_DEVICES_DINPUT8_H
#define DINPUTHOOK_DEVICES_DINPUT8_H
#include <initguid.h>
#include <dinput.h>
extern IDirectInputDevice8W *di8_stub_device;
#endif

120
src/main/dinput/dinput.c Normal file
View File

@@ -0,0 +1,120 @@
#include <windows.h>
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
#include "dinput/device_dinput8.h"
#include "dinput/dinput.h"
#include <stdbool.h>
#include "hook/com-proxy.h"
#include "hook/pe.h"
#include "hook/table.h"
#include "util/defs.h"
#include "util/log.h"
static HRESULT STDCALL my_DirectInput8Create(
HINSTANCE hinst,
DWORD dwVersion,
REFIID riidltf,
LPVOID *ppvOut,
LPVOID punkOuter);
static HRESULT(STDCALL *real_DirectInput8Create)(
HINSTANCE hinst,
DWORD dwVersion,
REFIID riidltf,
LPVOID *ppvOut,
LPVOID punkOuter);
static const struct hook_symbol dinput_syms[] = {
{
.name = "DirectInput8Create",
.patch = my_DirectInput8Create,
.link = (void **) &real_DirectInput8Create,
},
};
static HRESULT STDCALL my_CreateDevice(
IDirectInput8W *self,
REFGUID rguid,
LPDIRECTINPUTDEVICE8W *lplpDirectInputDevice,
LPUNKNOWN pUnkOuter)
{
log_misc("IDirectInput8::CreateDevice hook hit");
if (lplpDirectInputDevice == NULL) {
return DIERR_INVALIDPARAM;
}
if (IsEqualGUID(rguid, &GUID_SysKeyboard) ||
IsEqualGUID(rguid, &GUID_SysMouse)) {
log_misc("Returning stub device");
*lplpDirectInputDevice = di8_stub_device;
di8_stub_device->lpVtbl->AddRef(di8_stub_device);
return DI_OK;
}
return DIERR_NOINTERFACE;
}
static HRESULT STDCALL my_EnumDevices(
IDirectInput8W *self,
DWORD dwDevType,
LPDIENUMDEVICESCALLBACKW lpCallback,
LPVOID pvRef,
DWORD dwFlags)
{
log_misc("IDirectInput8::EnumDevices hook hit");
return DI_OK;
}
static HRESULT STDCALL my_DirectInput8Create(
HINSTANCE hinst,
DWORD dwVersion,
REFIID riidltf,
LPVOID *ppvOut,
LPVOID punkOuter)
{
IDirectInput8W *api;
IDirectInput8WVtbl *api_vtbl;
struct com_proxy *api_proxy;
HRESULT res;
log_info("DirectInput8Create hook hit");
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) {
log_warning("Wrapping com proxy failed: %08lx", res);
return res;
}
api_vtbl = api_proxy->vptr;
api_vtbl->EnumDevices = my_EnumDevices;
api_vtbl->CreateDevice = my_CreateDevice;
*(IDirectInput8W **) ppvOut = (IDirectInput8W *) api_proxy;
return res;
}
void dinput_init(void)
{
hook_table_apply(NULL, "dinput8.dll", dinput_syms, lengthof(dinput_syms));
log_info("Inserted dinput hooks");
}

10
src/main/dinput/dinput.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef DINPUTHOOK_DINPUT_H
#define DINPUTHOOK_DINPUT_H
#include <windows.h>
// This is to stub out the dinput device
// Such that rawinput can still poll keyboards
void dinput_init(void);
#endif

View File

@@ -53,7 +53,14 @@ void ezusb_emu_device_hook_init(struct ezusb_emu_msg_hook *msg_hook)
{
log_assert(ezusb_emu_fd == NULL);
ezusb_emu_fd = iohook_open_dummy_fd();
HRESULT hr;
hr = iohook_open_nul_fd(&ezusb_emu_fd);
if (hr != S_OK) {
log_fatal("Opening nul fd failed: %08lx", hr);
}
ezusb_emu_dev_fx_msg_hook = msg_hook;
}
@@ -70,7 +77,7 @@ HRESULT
ezusb_emu_device_dispatch_irp(struct irp *irp)
{
if (irp->op != IRP_OP_OPEN && irp->fd != ezusb_emu_fd) {
return irp_invoke_next(irp);
return iohook_invoke_next(irp);
}
/* read/write are not supported, and the game-side EZUSB code constantly
@@ -98,7 +105,7 @@ static HRESULT ezusb_open(struct irp *irp)
log_assert(irp != NULL);
if (!wstr_eq(irp->open_filename, L"\\\\.\\Ezusb-0")) {
return irp_invoke_next(irp);
return iohook_invoke_next(irp);
}
irp->fd = ezusb_emu_fd;

View File

@@ -160,6 +160,10 @@ static HRESULT ezusb_iidx_emu_msg_interrupt_read(struct iobuf *read)
otherwise the game's fpga check will fail */
msg_resp->fpga2_check_flag_unkn = 2;
#ifdef EZUSB_IIDX_EMU_D01_BOARD
msg_resp->inverted_pad &= ~(1 << 4);
#endif
read->pos = sizeof(*msg_resp);
return S_OK;

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