Bemanitools v5.26 release
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
libs += ezusb-emu
|
||||
|
||||
libs_ezusb-emu := \
|
||||
ezusb \
|
||||
|
||||
src_ezusb-emu := \
|
||||
desc.c \
|
||||
device.c \
|
||||
util.c
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifndef EZUSB_EMU_CONF_H
|
||||
#define EZUSB_EMU_CONF_H
|
||||
|
||||
//#define EZUSB_EMU_DEBUG_DUMP
|
||||
//#define EZUSB_EMU_FW_DUMP
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "ezusb-emu/desc.h"
|
||||
|
||||
const struct ezusb_emu_desc_device ezusb_emu_desc_device = {
|
||||
.setupapi = {
|
||||
.device_guid = {
|
||||
0xAE18AA60,
|
||||
0x7F6A,
|
||||
0x11D4,
|
||||
{ 0x97, 0xDD, 0x00, 0x01, 0x02, 0x29, 0xB9, 0x59 }
|
||||
},
|
||||
.device_desc = "Cypress EZ-USB (2235) - EEPROM missing",
|
||||
.device_path = "\\\\.\\Ezusb-0"
|
||||
},
|
||||
.vid = 0x0547,
|
||||
.pid = 0x2235,
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef EZUSB_EMU_DESC_H
|
||||
#define EZUSB_EMU_DESC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hooklib/setupapi.h"
|
||||
|
||||
struct ezusb_emu_desc_device {
|
||||
struct hook_setupapi_data setupapi;
|
||||
uint16_t vid;
|
||||
uint16_t pid;
|
||||
};
|
||||
|
||||
/* C02 IO board */
|
||||
extern const struct ezusb_emu_desc_device ezusb_emu_desc_device;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,308 @@
|
||||
#define LOG_MODULE "ezusb-emu-device"
|
||||
|
||||
#include <windows.h>
|
||||
#include <setupapi.h>
|
||||
#include <usb100.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "ezusb/ezusbsys2.h"
|
||||
#include "ezusb/util.h"
|
||||
|
||||
#include "ezusb-emu/conf.h"
|
||||
#include "ezusb-emu/desc.h"
|
||||
#include "ezusb-emu/device.h"
|
||||
#include "ezusb-emu/msg.h"
|
||||
#include "ezusb-emu/util.h"
|
||||
|
||||
#include "hook/iohook.h"
|
||||
|
||||
#include "imports/avs.h"
|
||||
|
||||
#include "util/fs.h"
|
||||
#include "util/hex.h"
|
||||
#include "util/iobuf.h"
|
||||
#include "util/log.h"
|
||||
#include "util/str.h"
|
||||
|
||||
static HRESULT ezusb_get_device_descriptor(struct irp *irp);
|
||||
static HRESULT ezusb_vendor_req(struct irp *irp);
|
||||
static HRESULT ezusb_upload_fw(struct irp *irp);
|
||||
static HRESULT ezusb_pipe_read(struct irp *irp);
|
||||
static HRESULT ezusb_pipe_write(struct irp *irp);
|
||||
|
||||
static HRESULT ezusb_open(struct irp *irp);
|
||||
static HRESULT ezusb_ioctl(struct irp *irp);
|
||||
|
||||
enum ezusb_pipe {
|
||||
/* This is just the NT driver API. Add 1 to get the actual EP number. */
|
||||
EZUSB_PIPE_INTERRUPT_OUT = 0,
|
||||
EZUSB_PIPE_INTERRUPT_IN = 1,
|
||||
EZUSB_PIPE_BULK_OUT = 2,
|
||||
EZUSB_PIPE_BULK_IN = 3
|
||||
};
|
||||
|
||||
static HANDLE ezusb_emu_fd;
|
||||
static struct ezusb_firmware* ezusb_emu_firmware;
|
||||
static struct ezusb_emu_msg_hook* ezusb_emu_dev_fx_msg_hook;
|
||||
|
||||
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();
|
||||
ezusb_emu_dev_fx_msg_hook = msg_hook;
|
||||
}
|
||||
|
||||
void ezusb_emu_device_hook_fini(void)
|
||||
{
|
||||
if (ezusb_emu_fd != NULL) {
|
||||
CloseHandle(ezusb_emu_fd);
|
||||
}
|
||||
|
||||
ezusb_emu_fd = NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* read/write are not supported, and the game-side EZUSB code constantly
|
||||
churns through FDs opening and closing them (so we silently acknowledge
|
||||
CloseHandle calls and don't even log them). */
|
||||
|
||||
switch (irp->op) {
|
||||
case IRP_OP_OPEN: return ezusb_open(irp);
|
||||
case IRP_OP_CLOSE: return S_OK;
|
||||
case IRP_OP_IOCTL: return ezusb_ioctl(irp);
|
||||
default: return E_NOTIMPL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* WIN32 I/O AND IOHOOK LAYER
|
||||
*/
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
irp->fd = ezusb_emu_fd;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT ezusb_ioctl(struct irp *irp)
|
||||
{
|
||||
/* For debugging */
|
||||
#ifdef EZUSB_EMU_DEBUG_DUMP
|
||||
/* For debugging */
|
||||
ezusb_emu_util_log_usb_msg("BEFORE", irp->ioctl, irp->read.bytes,
|
||||
irp->read.nbytes, irp->read.bytes, irp->read.nbytes, irp->write.bytes,
|
||||
irp->write.nbytes);
|
||||
#endif
|
||||
|
||||
/* Cases are listed in order of first receipt */
|
||||
switch (irp->ioctl) {
|
||||
case IOCTL_Ezusb_GET_DEVICE_DESCRIPTOR:
|
||||
return ezusb_get_device_descriptor(irp);
|
||||
|
||||
case IOCTL_Ezusb_VENDOR_REQUEST:
|
||||
return ezusb_vendor_req(irp);
|
||||
|
||||
case IOCTL_EZUSB_ANCHOR_DOWNLOAD:
|
||||
return ezusb_upload_fw(irp);
|
||||
|
||||
case IOCTL_EZUSB_BULK_READ:
|
||||
/* Misnomer: can be bulk or interrupt. */
|
||||
return ezusb_pipe_read(irp);
|
||||
|
||||
case IOCTL_EZUSB_BULK_WRITE:
|
||||
/* Ditto. */
|
||||
return ezusb_pipe_write(irp);
|
||||
|
||||
default:
|
||||
log_warning("Unknown ioctl %08x", irp->ioctl);
|
||||
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
#ifdef EZUSB_EMU_DEBUG_DUMP
|
||||
/* For debugging */
|
||||
ezusb_emu_util_log_usb_msg("AFTER", irp->ioctl, irp->read.bytes,
|
||||
irp->read.nbytes, irp->read.bytes, irp->read.nbytes, irp->write.bytes,
|
||||
irp->write.nbytes);
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
* USB TRANSFER LAYER
|
||||
*/
|
||||
|
||||
static HRESULT ezusb_get_device_descriptor(struct irp *irp)
|
||||
{
|
||||
USB_DEVICE_DESCRIPTOR *desc;
|
||||
|
||||
log_assert(irp != NULL);
|
||||
|
||||
if (irp->read.nbytes < sizeof(*desc)) {
|
||||
log_warning("USB_DEVICE_DESCRIPTOR buffer too small");
|
||||
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
desc = (USB_DEVICE_DESCRIPTOR *) irp->read.bytes;
|
||||
|
||||
memset(desc, 0, sizeof(*desc));
|
||||
desc->idVendor = ezusb_emu_desc_device.vid;
|
||||
desc->idProduct = ezusb_emu_desc_device.pid;
|
||||
irp->read.pos = sizeof(*desc);
|
||||
|
||||
log_misc(
|
||||
"get_device_descriptor: vid %02x, pid %02x",
|
||||
desc->idVendor,
|
||||
desc->idProduct);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT ezusb_vendor_req(struct irp *irp)
|
||||
{
|
||||
VENDOR_OR_CLASS_REQUEST_CONTROL *vc;
|
||||
|
||||
log_assert(irp != NULL);
|
||||
|
||||
if (irp->write.nbytes < sizeof(*vc)) {
|
||||
log_warning("VENDOR_OR_CLASS_REQUEST_CONTROL buffer too small");
|
||||
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
vc = (VENDOR_OR_CLASS_REQUEST_CONTROL *) irp->write.bytes;
|
||||
|
||||
log_misc(
|
||||
"vendor req %02x, value %04x, index %04x",
|
||||
vc->request,
|
||||
vc->value,
|
||||
vc->index);
|
||||
|
||||
if (vc->request == 0x00 && vc->value == 0x0001 && vc->index == 0x0100) {
|
||||
log_misc("vendor req: reset hold, starting fw download...");
|
||||
ezusb_emu_firmware = ezusb_firmware_alloc();
|
||||
} else if (vc->request == 0x00 && vc->value == 0x0001 && vc->index == 0x0000) {
|
||||
log_misc("vendor req: reset release, finished fw download");
|
||||
/* FW download finished, reset 8051 and start the downloaded FW */
|
||||
|
||||
ezusb_emu_firmware->crc = ezusb_firmware_crc(ezusb_emu_firmware);
|
||||
|
||||
#ifdef EZUSB_EMU_FW_DUMP
|
||||
if (!ezusb_firmware_save("ezusb_fx.bin", ezusb_emu_firmware)) {
|
||||
log_fatal("Saving dumped firmware failed");
|
||||
} else {
|
||||
log_misc("firmware dumped do ezusb_fx.bin file");
|
||||
}
|
||||
#endif
|
||||
|
||||
free(ezusb_emu_firmware);
|
||||
ezusb_emu_firmware = NULL;
|
||||
} else {
|
||||
log_warning("VENDOR_OR_CLASS_REQUEST_CONTROL unknown request");
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT ezusb_upload_fw(struct irp *irp)
|
||||
{
|
||||
ANCHOR_DOWNLOAD_CONTROL *hdr;
|
||||
|
||||
log_assert(irp != NULL);
|
||||
|
||||
if (irp->write.nbytes < sizeof(*hdr)) {
|
||||
log_warning("ANCHOR_DOWNLOAD_CONTROL buffer too small");
|
||||
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
hdr = (ANCHOR_DOWNLOAD_CONTROL *) irp->write.bytes;
|
||||
|
||||
/* The semantics for this ioctl are FUCKED! The second buffer is
|
||||
supposed to receive data, not send it! */
|
||||
|
||||
log_misc(
|
||||
"upload_fw: offset: %04x, nbytes: %04x",
|
||||
hdr->Offset,
|
||||
irp->read.nbytes);
|
||||
ezusb_firmware_add_segment(ezusb_emu_firmware,
|
||||
ezusb_firmware_segment_alloc(hdr->Offset, irp->read.nbytes,
|
||||
(void*) irp->read.bytes));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT ezusb_pipe_read(struct irp *irp)
|
||||
{
|
||||
BULK_TRANSFER_CONTROL *ctl;
|
||||
|
||||
log_assert(irp != NULL);
|
||||
|
||||
if (irp->write.nbytes < sizeof(*ctl)) {
|
||||
log_warning("BULK_TRANSFER_CONTROL buffer too small");
|
||||
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
ctl = (BULK_TRANSFER_CONTROL *) irp->write.bytes;
|
||||
|
||||
switch (ctl->pipeNum) {
|
||||
case EZUSB_PIPE_INTERRUPT_IN:
|
||||
return ezusb_emu_dev_fx_msg_hook->interrupt_read(&irp->read);
|
||||
|
||||
case EZUSB_PIPE_BULK_IN:
|
||||
return ezusb_emu_dev_fx_msg_hook->bulk_read(&irp->read);
|
||||
|
||||
default:
|
||||
log_warning("No such read pipe: %u", (unsigned int) ctl->pipeNum);
|
||||
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT ezusb_pipe_write(struct irp *irp)
|
||||
{
|
||||
BULK_TRANSFER_CONTROL *ctl;
|
||||
struct const_iobuf write;
|
||||
|
||||
if (irp->write.nbytes < sizeof(*ctl)) {
|
||||
log_warning("BULK_TRANSFER_CONTROL buffer too small");
|
||||
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
ctl = (BULK_TRANSFER_CONTROL *) irp->write.bytes;
|
||||
|
||||
/* ugh */
|
||||
write.bytes = irp->read.bytes;
|
||||
write.nbytes = irp->read.nbytes;
|
||||
write.pos = 0;
|
||||
|
||||
switch (ctl->pipeNum) {
|
||||
case EZUSB_PIPE_INTERRUPT_OUT:
|
||||
return ezusb_emu_dev_fx_msg_hook->interrupt_write(&write);
|
||||
|
||||
case EZUSB_PIPE_BULK_OUT:
|
||||
return ezusb_emu_dev_fx_msg_hook->bulk_write(&write);
|
||||
|
||||
default:
|
||||
log_warning("No such write pipe: %u", (unsigned int) ctl->pipeNum);
|
||||
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef EZUSB_EMU_DEVICE_H
|
||||
#define EZUSB_EMU_DEVICE_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "ezusb-emu/msg.h"
|
||||
|
||||
#include "hook/iohook.h"
|
||||
|
||||
/**
|
||||
* Hook IO functions to intercept with ezusb (IIDX C02) communication and
|
||||
* detour to our emulation code.
|
||||
*
|
||||
* @param msg_hook Hook functions to dispatch ezusb interrupt and bulk device
|
||||
* messages to
|
||||
*/
|
||||
void ezusb_emu_device_hook_init(struct ezusb_emu_msg_hook* msg_hook);
|
||||
|
||||
/**
|
||||
* Cleanup the hooked IO functions.
|
||||
*/
|
||||
void ezusb_emu_device_hook_fini(void);
|
||||
|
||||
/**
|
||||
* Iohook interface.
|
||||
*/
|
||||
HRESULT ezusb_emu_device_dispatch_irp(struct irp *irp);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef EZUSB_EMU_MSG_H
|
||||
#define EZUSB_EMU_MSG_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "util/iobuf.h"
|
||||
|
||||
struct ezusb_emu_msg_hook {
|
||||
HRESULT (*interrupt_read)(struct iobuf *read);
|
||||
HRESULT (*interrupt_write)(struct const_iobuf *write);
|
||||
HRESULT (*bulk_read)(struct iobuf *read);
|
||||
HRESULT (*bulk_write)(struct const_iobuf *write);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
#define LOG_MODULE "ezusb-emu-util"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <setupapi.h>
|
||||
#include <usb100.h>
|
||||
|
||||
#include "ezusb-emu/util.h"
|
||||
|
||||
#include "util/hex.h"
|
||||
#include "util/log.h"
|
||||
|
||||
enum ezusb_pipe {
|
||||
/* This is just the NT driver API. Add 1 to get the actual EP number. */
|
||||
EZUSB_PIPE_INTERRUPT_OUT = 0,
|
||||
EZUSB_PIPE_INTERRUPT_IN = 1,
|
||||
EZUSB_PIPE_BULK_OUT = 2,
|
||||
EZUSB_PIPE_BULK_IN = 3
|
||||
};
|
||||
|
||||
void ezusb_emu_util_log_usb_msg(const char* prefix, uint32_t ctl_code,
|
||||
const BULK_TRANSFER_CONTROL *ctl, uint32_t ctl_size, void* header,
|
||||
uint32_t header_bytes, void* data, uint32_t data_bytes)
|
||||
{
|
||||
char header_str[4096];
|
||||
char data_str[4096];
|
||||
const char* ctl_code_str;
|
||||
|
||||
switch (ctl_code) {
|
||||
case IOCTL_Ezusb_GET_DEVICE_DESCRIPTOR:
|
||||
ctl_code_str = "GET_DEVICE_DESCRIPTOR";
|
||||
break;
|
||||
|
||||
case IOCTL_Ezusb_VENDOR_REQUEST:
|
||||
ctl_code_str = "VENDOR_REQUEST";
|
||||
break;
|
||||
|
||||
case IOCTL_EZUSB_ANCHOR_DOWNLOAD:
|
||||
ctl_code_str = "ANCHOR_DOWNLOAD";
|
||||
break;
|
||||
|
||||
case IOCTL_EZUSB_BULK_READ:
|
||||
if (ctl->pipeNum == EZUSB_PIPE_INTERRUPT_IN) {
|
||||
ctl_code_str = "INT_READ";
|
||||
} else if (ctl->pipeNum == EZUSB_PIPE_BULK_IN) {
|
||||
ctl_code_str = "BULK_READ";
|
||||
} else {
|
||||
ctl_code_str = "INVALID_READ";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case IOCTL_EZUSB_BULK_WRITE:
|
||||
if (ctl->pipeNum == EZUSB_PIPE_INTERRUPT_OUT) {
|
||||
ctl_code_str = "INT_WRITE";
|
||||
} else if (ctl->pipeNum == EZUSB_PIPE_BULK_OUT) {
|
||||
ctl_code_str = "BULK_WRITE";
|
||||
} else {
|
||||
ctl_code_str = "INVALID_WRITE";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
ctl_code_str = "UNKNOWN";
|
||||
break;
|
||||
}
|
||||
|
||||
hex_encode_uc(header, header_bytes, header_str, sizeof(header_str));
|
||||
hex_encode_uc(data, data_bytes, data_str, sizeof(data_str));
|
||||
|
||||
log_warning("[EZUSB DUMP %s][%s] header(%d) %s |||| data(%d) %s",
|
||||
prefix, ctl_code_str, header_bytes, header_str, data_bytes, data_str);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef EZUSB_EMU_UTIL_H
|
||||
#define EZUSB_EMU_UTIL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <setupapi.h>
|
||||
#include <usb100.h>
|
||||
|
||||
#include "ezusb/ezusbsys2.h"
|
||||
|
||||
#include "hook/iohook.h"
|
||||
|
||||
void ezusb_emu_util_log_usb_msg(const char* prefix, uint32_t ctl_code,
|
||||
const BULK_TRANSFER_CONTROL *ctl, uint32_t ctl_size, void* header,
|
||||
uint32_t header_bytes, void* data, uint32_t data_bytes);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user