taitools/idmac/jvs.c

135 lines
3.0 KiB
C
Raw Permalink Normal View History

2024-02-06 08:24:58 +00:00
#define WIN32_NO_STATUS
#include <windows.h>
#undef WIN32_NO_STATUS
#include <winternl.h>
#include <ntstatus.h>
#include <assert.h>
#include <stddef.h>
2024-02-10 22:48:10 +00:00
#include "idmac/jvs.h"
2024-02-06 08:24:58 +00:00
#include "hook/iobuf.h"
#include "hook/iohook.h"
2024-02-20 07:17:12 +00:00
#include "hooklib/uart.h"
2024-02-06 08:24:58 +00:00
#include "hooklib/setupapi.h"
#include "jvs/jvs-bus.h"
#include "util/dprintf.h"
#include "util/dump.h"
#include "util/str.h"
enum {
JVS_IOCTL_HELLO = 0x80006004,
JVS_IOCTL_SENSE = 0x8000600C,
JVS_IOCTL_TRANSACT = 0x8000E008,
};
static HRESULT jvs_handle_irp(struct irp *irp);
2024-02-20 07:17:12 +00:00
static HRESULT jvs_handle_irp_locked(struct irp *irp);
2024-02-06 08:24:58 +00:00
2024-02-20 07:17:12 +00:00
static CRITICAL_SECTION jvs_lock;
static struct uart jvs_uart;
static uint8_t jvs_written_bytes[516];
static uint8_t jvs_readable_bytes[516];
2024-02-06 08:24:58 +00:00
static struct jvs_node *jvs_root;
static jvs_provider_t jvs_provider;
HRESULT jvs_hook_init(const struct jvs_config *cfg, jvs_provider_t provider)
{
HRESULT hr;
assert(cfg != NULL);
if (!cfg->enable) {
return S_FALSE;
}
2024-02-20 07:17:12 +00:00
InitializeCriticalSection(&jvs_lock);
2024-02-06 08:24:58 +00:00
2024-02-20 07:17:12 +00:00
uart_init(&jvs_uart, 2);
jvs_uart.written.bytes = jvs_written_bytes;
jvs_uart.written.nbytes = sizeof(jvs_written_bytes);
jvs_uart.readable.bytes = jvs_readable_bytes;
jvs_uart.readable.nbytes = sizeof(jvs_readable_bytes);
2024-02-06 08:24:58 +00:00
jvs_provider = provider;
2024-02-20 07:17:12 +00:00
return iohook_push_handler(jvs_handle_irp);
2024-02-06 08:24:58 +00:00
}
static HRESULT jvs_handle_irp(struct irp *irp)
{
HRESULT hr;
2024-02-20 07:17:12 +00:00
assert(irp != NULL);
2024-02-06 08:24:58 +00:00
2024-02-20 07:17:12 +00:00
if (!uart_match_irp(&jvs_uart, irp)) {
return iohook_invoke_next(irp);
2024-02-06 08:24:58 +00:00
}
2024-02-20 07:17:12 +00:00
EnterCriticalSection(&jvs_lock);
hr = jvs_handle_irp_locked(irp);
LeaveCriticalSection(&jvs_lock);
2024-02-06 08:24:58 +00:00
2024-02-20 07:17:12 +00:00
return hr;
2024-02-06 08:24:58 +00:00
}
2024-02-20 07:17:12 +00:00
static HRESULT jvs_handle_irp_locked(struct irp *irp)
2024-02-06 08:24:58 +00:00
{
2024-02-20 07:17:12 +00:00
#if 0
dprintf("\nJVS Port: Outbound frame:\n");
dump_const_iobuf(&irp->write);
#endif
struct iobuf req_iobuf;
2024-02-06 08:24:58 +00:00
HRESULT hr;
2024-02-20 07:17:12 +00:00
struct jvs_node *root;
2024-02-06 08:24:58 +00:00
2024-02-20 07:17:12 +00:00
if (irp->op == IRP_OP_OPEN) {
dprintf("iDmac JVS: Starting backend\n");
if (jvs_provider != NULL) {
hr = jvs_provider(&root);
2024-02-06 08:24:58 +00:00
2024-02-20 07:17:12 +00:00
if (SUCCEEDED(hr)) {
jvs_root = root;
}
2024-02-06 08:24:58 +00:00
}
}
2024-02-20 07:17:12 +00:00
hr = uart_handle_irp(&jvs_uart, irp);
2024-02-06 08:24:58 +00:00
2024-02-20 07:17:12 +00:00
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
return hr;
}
2024-02-06 08:24:58 +00:00
jvs_bus_transact(jvs_root, irp->write.bytes, irp->write.nbytes, &irp->read);
2024-02-20 07:17:12 +00:00
#if 1
2024-02-06 08:24:58 +00:00
dprintf("JVS Port: 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,
2024-02-20 07:17:12 +00:00
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. */
2024-02-06 08:24:58 +00:00
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;
}
}