taitools/idmac/jvs.c
2024-02-21 03:43:44 -05:00

140 lines
3.1 KiB
C

#define WIN32_NO_STATUS
#include <windows.h>
#undef WIN32_NO_STATUS
#include <winternl.h>
#include <ntstatus.h>
#include <assert.h>
#include <stddef.h>
#include "idmac/jvs.h"
#include "hook/iobuf.h"
#include "hook/iohook.h"
#include "hooklib/uart.h"
#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);
static HRESULT jvs_handle_irp_locked(struct irp *irp);
static CRITICAL_SECTION jvs_lock;
static struct uart jvs_uart;
static uint8_t jvs_written_bytes[516];
static uint8_t jvs_readable_bytes[516];
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;
}
InitializeCriticalSection(&jvs_lock);
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);
jvs_provider = provider;
return iohook_push_handler(jvs_handle_irp);
}
static HRESULT jvs_handle_irp(struct irp *irp)
{
HRESULT hr;
assert(irp != NULL);
if (!uart_match_irp(&jvs_uart, irp)) {
return iohook_invoke_next(irp);
}
EnterCriticalSection(&jvs_lock);
hr = jvs_handle_irp_locked(irp);
LeaveCriticalSection(&jvs_lock);
return hr;
}
static HRESULT jvs_handle_irp_locked(struct irp *irp)
{
#if 0
dprintf("\nJVS Port: Outbound frame:\n");
dump_const_iobuf(&irp->write);
#endif
struct iobuf req_iobuf;
HRESULT hr;
struct jvs_node *root;
if (irp->op == IRP_OP_OPEN) {
dprintf("iDmac JVS: Starting backend\n");
if (jvs_provider != NULL) {
hr = jvs_provider(&root);
if (SUCCEEDED(hr)) {
jvs_root = root;
}
}
}
hr = uart_handle_irp(&jvs_uart, irp);
if (irp->ioctl == IOCTL_SERIAL_GET_MODEMSTATUS) {
irp->modem_state = MS_CTS_ON;
return S_OK;
}
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
return hr;
}
jvs_bus_transact(jvs_root, irp->write.bytes, irp->write.nbytes, &irp->read);
#if 1
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,
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;
}
}