Files
2026-03-14 01:12:10 -04:00

153 lines
3.7 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 uint8_t temp_bytes[516];
static struct jvs_node *jvs_root;
static jvs_provider_t jvs_provider;
static struct iobuf tmp = {
.nbytes = 516,
.pos = 0,
.bytes = temp_bytes
};
static bool last = false;
static uint8_t num_cts = 0;
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, cfg->port);
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;
}
}
}
if (irp->op == IRP_OP_IOCTL) {
switch (irp->ioctl) {
case IOCTL_SERIAL_GET_MODEMSTATUS:
//jvs_uart.cts_on = jvs_root->sense_out;
//dprintf("JVS: Set CTS to %X\n", jvs_root->sense_out);
jvs_uart.cts_on = !jvs_root->sense_out; // ??
break;
case IOCTL_SERIAL_GET_COMMSTATUS:
//dprintf("JVS: Set cbInQue to %d\n", (int)tmp.pos);
jvs_uart.readable.pos = tmp.pos;
default: break;
}
}
if (irp->op == IRP_OP_READ) {
if (irp->read.nbytes == 1) {
iobuf_write_8(&irp->read, 1);
return S_OK;
}
if (irp->read.nbytes >= tmp.pos) {
//dprintf("JVS: Readable buffer is %d / %d\n", (int)irp->read.nbytes, (int)tmp.pos);
iobuf_write(&irp->read, tmp.bytes, tmp.pos);
tmp.pos = 0;
} else {
dprintf("JVS: READ need %d bytes but only have room for %d\n", tmp.pos, irp->read.nbytes);
iobuf_write(&irp->read, tmp.bytes, irp->read.nbytes);
tmp.pos -= irp->read.nbytes;
}
}
hr = uart_handle_irp(&jvs_uart, irp);
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
return hr;
}
jvs_bus_transact(jvs_root, irp->write.bytes, irp->write.nbytes, &tmp);
jvs_uart.written.pos = 0;
return S_OK;
}