From 0929beae117a756ef62fd34d4a72a04c327a1ebf Mon Sep 17 00:00:00 2001 From: Tau Date: Thu, 8 Nov 2018 14:20:48 -0500 Subject: [PATCH] nu/jvs.c: Add emulated JVS controller --- nu/guid.c | 1 + nu/jvs.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++++ nu/jvs.h | 15 +++++ nu/meson.build | 2 + 4 files changed, 189 insertions(+) create mode 100644 nu/jvs.c create mode 100644 nu/jvs.h diff --git a/nu/guid.c b/nu/guid.c index c01c1b6..8a81fa8 100644 --- a/nu/guid.c +++ b/nu/guid.c @@ -4,4 +4,5 @@ #include "nu/ds.h" #include "nu/eeprom.h" #include "nu/gpio.h" +#include "nu/jvs.h" #include "nu/sram.h" diff --git a/nu/jvs.c b/nu/jvs.c new file mode 100644 index 0000000..e86130e --- /dev/null +++ b/nu/jvs.c @@ -0,0 +1,171 @@ +#include +#include + +#include +#include + +#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; + } +} diff --git a/nu/jvs.h b/nu/jvs.h new file mode 100644 index 0000000..2ab940b --- /dev/null +++ b/nu/jvs.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#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); diff --git a/nu/meson.build b/nu/meson.build index 293fc67..c49261c 100644 --- a/nu/meson.build +++ b/nu/meson.build @@ -15,6 +15,8 @@ nu_lib = static_library( 'gpio.c', 'gpio.h', 'guid.c', + 'jvs.c', + 'jvs.h', 'hwmon.c', 'hwmon.h', 'nusec.c',