mirror of
https://gitea.tendokyu.moe/Dniel97/segatools.git
synced 2024-11-24 05:20:10 +01:00
nu/jvs.c: Add emulated JVS controller
This commit is contained in:
parent
e2f554f5bb
commit
0929beae11
@ -4,4 +4,5 @@
|
||||
#include "nu/ds.h"
|
||||
#include "nu/eeprom.h"
|
||||
#include "nu/gpio.h"
|
||||
#include "nu/jvs.h"
|
||||
#include "nu/sram.h"
|
||||
|
171
nu/jvs.c
Normal file
171
nu/jvs.c
Normal file
@ -0,0 +1,171 @@
|
||||
#include <windows.h>
|
||||
#include <ntstatus.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "hook/iobuf.h"
|
||||
#include "hook/iohook.h"
|
||||
|
||||
#include "jvs/jvs-bus.h"
|
||||
|
||||
#include "nu/jvs.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/dump.h"
|
||||
#include "util/setupapi.h"
|
||||
|
||||
enum {
|
||||
JVS_IOCTL_HELLO = 0x80006004,
|
||||
JVS_IOCTL_SENSE = 0x8000600C,
|
||||
JVS_IOCTL_TRANSACT = 0x8000E008,
|
||||
};
|
||||
|
||||
static HRESULT jvs_handle_irp(struct irp *irp);
|
||||
static HRESULT jvs_handle_open(struct irp *irp);
|
||||
static HRESULT jvs_handle_close(struct irp *irp);
|
||||
static HRESULT jvs_handle_ioctl(struct irp *irp);
|
||||
|
||||
static HRESULT jvs_ioctl_hello(struct irp *irp);
|
||||
static HRESULT jvs_ioctl_sense(struct irp *irp);
|
||||
static HRESULT jvs_ioctl_transact(struct irp *irp);
|
||||
|
||||
static HANDLE jvs_fd;
|
||||
static struct jvs_node *jvs_root;
|
||||
|
||||
void jvs_hook_init(void)
|
||||
{
|
||||
jvs_fd = iohook_open_dummy_fd();
|
||||
iohook_push_handler(jvs_handle_irp);
|
||||
setupapi_add_phantom_dev(&jvs_guid, L"$jvs");
|
||||
}
|
||||
|
||||
void jvs_attach(struct jvs_node *root)
|
||||
{
|
||||
jvs_root = root;
|
||||
}
|
||||
|
||||
static HRESULT jvs_handle_irp(struct irp *irp)
|
||||
{
|
||||
assert(irp != NULL);
|
||||
|
||||
if (irp->op != IRP_OP_OPEN && irp->fd != jvs_fd) {
|
||||
return iohook_invoke_next(irp);
|
||||
}
|
||||
|
||||
switch (irp->op) {
|
||||
case IRP_OP_OPEN: return jvs_handle_open(irp);
|
||||
case IRP_OP_CLOSE: return jvs_handle_close(irp);
|
||||
case IRP_OP_IOCTL: return jvs_handle_ioctl(irp);
|
||||
default: return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT jvs_handle_open(struct irp *irp)
|
||||
{
|
||||
if (wcscmp(irp->open_filename, L"$jvs") != 0) {
|
||||
return iohook_invoke_next(irp);
|
||||
}
|
||||
|
||||
dprintf("JVS Controller: Open device\n");
|
||||
irp->fd = jvs_fd;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT jvs_handle_close(struct irp *irp)
|
||||
{
|
||||
dprintf("JVS Controller: Close device\n");
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT jvs_handle_ioctl(struct irp *irp)
|
||||
{
|
||||
switch (irp->ioctl) {
|
||||
case JVS_IOCTL_HELLO:
|
||||
return jvs_ioctl_hello(irp);
|
||||
|
||||
case JVS_IOCTL_SENSE:
|
||||
return jvs_ioctl_sense(irp);
|
||||
|
||||
case JVS_IOCTL_TRANSACT:
|
||||
return jvs_ioctl_transact(irp);
|
||||
|
||||
default:
|
||||
dprintf("JVS Controller: Unknown ioctl %#x\n", irp->ioctl);
|
||||
|
||||
return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT jvs_ioctl_hello(struct irp *irp)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
// uuh fucked if i know
|
||||
|
||||
dprintf("JVS Controller: Port startup (?)\n");
|
||||
|
||||
iobuf_write_8(&irp->read, 0);
|
||||
hr = iobuf_write_8(&irp->read, 0);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT jvs_ioctl_sense(struct irp *irp)
|
||||
{
|
||||
uint8_t code;
|
||||
bool sense;
|
||||
|
||||
if (jvs_root != NULL) {
|
||||
sense = jvs_root->sense(jvs_root);
|
||||
|
||||
if (sense) {
|
||||
dprintf("JVS Controller: Sense line 2.5 V (address unassigned)\n");
|
||||
code = 3;
|
||||
} else {
|
||||
dprintf("JVS Controller: Sense line 0.0 V (address assigned)\n");
|
||||
code = 2;
|
||||
}
|
||||
} else {
|
||||
dprintf("JVS Controller: Sense line 5.0 V (no downstream PCB)\n");
|
||||
code = 1;
|
||||
}
|
||||
|
||||
return iobuf_write_8(&irp->read, code);
|
||||
}
|
||||
|
||||
static HRESULT jvs_ioctl_transact(struct irp *irp)
|
||||
{
|
||||
#if 0
|
||||
dprintf("\nJVS Controller: Outbound frame:\n");
|
||||
dump_const_iobuf(&irp->write);
|
||||
#endif
|
||||
|
||||
jvs_bus_transact(jvs_root, irp->write.bytes, irp->write.nbytes, &irp->read);
|
||||
|
||||
#if 0
|
||||
dprintf("JVS Controller: Inbound frame:\n");
|
||||
dump_iobuf(&irp->read);
|
||||
dprintf("\n");
|
||||
#endif
|
||||
|
||||
if (irp->read.pos == 0) {
|
||||
/* The un-acked JVS reset command must return ERROR_NO_DATA_DETECTED,
|
||||
and this error must always be returned asynchronously. And since
|
||||
async I/O comes from the NT kernel, we have to return that win32
|
||||
error as the equivalent NTSTATUS. */
|
||||
|
||||
if (irp->ovl == NULL || irp->ovl->hEvent == NULL) {
|
||||
return HRESULT_FROM_WIN32(ERROR_NO_DATA_DETECTED);
|
||||
}
|
||||
|
||||
irp->ovl->Internal = STATUS_NO_DATA_DETECTED;
|
||||
SetEvent(irp->ovl->hEvent);
|
||||
|
||||
return HRESULT_FROM_WIN32(ERROR_IO_PENDING);
|
||||
} else {
|
||||
return S_OK;
|
||||
}
|
||||
}
|
15
nu/jvs.h
Normal file
15
nu/jvs.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "jvs/jvs-bus.h"
|
||||
|
||||
DEFINE_GUID(
|
||||
jvs_guid,
|
||||
0xDB6BBB45,
|
||||
0xCC96,
|
||||
0x4288,
|
||||
0xAA, 0x00, 0x6C, 0x00, 0xD7, 0x67, 0xBD, 0xBF);
|
||||
|
||||
void jvs_hook_init(void);
|
||||
void jvs_attach(struct jvs_node *root);
|
@ -15,6 +15,8 @@ nu_lib = static_library(
|
||||
'gpio.c',
|
||||
'gpio.h',
|
||||
'guid.c',
|
||||
'jvs.c',
|
||||
'jvs.h',
|
||||
'hwmon.c',
|
||||
'hwmon.h',
|
||||
'nusec.c',
|
||||
|
Loading…
Reference in New Issue
Block a user