UNSTABLE reader changes, bloat removal, card documentation

This commit is contained in:
Hay1tsme
2026-06-22 03:15:40 -04:00
parent c9a97c3fdb
commit f93eee3509
27 changed files with 85 additions and 1626 deletions
-8
View File
@@ -7,14 +7,6 @@
#include "board/config.h"
void io4_config_load(struct io4_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"io4", L"enable", 1, filename);
}
void k92x0249_config_load(struct k92x0249_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
-2
View File
@@ -3,12 +3,10 @@
#include <stdbool.h>
#include <stddef.h>
#include "board/io4.h"
#include "board/dongle.h"
#include "board/k92x0249.h"
#include "board/k9101258.h"
void io4_config_load(struct io4_config *cfg, const wchar_t *filename);
void k92x0249_config_load(struct k92x0249_config *cfg, const wchar_t *filename);
void k9101258_config_load(struct usbio_config *cfg, const wchar_t *filename);
void dongle_config_load(struct dongle_config *cfg, const wchar_t *filename);
-353
View File
@@ -1,353 +0,0 @@
#include <windows.h>
#include <devioctl.h>
#include <hidclass.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "board/config.h"
#include "board/guid.h"
#include "board/io4.h"
#include "hook/iobuf.h"
#include "hook/iohook.h"
#include "hooklib/setupapi.h"
#include "util/async.h"
#include "util/dprintf.h"
#pragma pack(push, 1)
enum {
IO4_CMD_SET_COMM_TIMEOUT = 0x01,
IO4_CMD_SET_SAMPLING_COUNT = 0x02,
IO4_CMD_CLEAR_BOARD_STATUS = 0x03,
IO4_CMD_SET_GENERAL_OUTPUT = 0x04,
IO4_CMD_SET_PWM_OUTPUT = 0x05,
IO4_CMD_UNIMPLEMENTED = 0x41,
IO4_CMD_UPDATE_FIRMWARE = 0x85,
};
struct io4_report_in {
uint8_t report_id;
uint16_t adcs[8];
uint16_t spinners[4];
uint16_t chutes[2];
uint16_t buttons[2];
uint8_t system_status;
uint8_t usb_status;
uint8_t unknown[29];
};
static_assert(sizeof(struct io4_report_in) == 0x40, "IO4 IN report size");
struct io4_report_out {
uint8_t report_id;
uint8_t cmd;
uint8_t payload[62];
};
static_assert(sizeof(struct io4_report_out) == 0x40, "IO4 OUT report size");
#pragma pack(pop)
static HRESULT io4_handle_irp(struct irp *irp);
static HRESULT io4_handle_open(struct irp *irp);
static HRESULT io4_handle_close(struct irp *irp);
static HRESULT io4_handle_read(struct irp *irp);
static HRESULT io4_handle_write(struct irp *irp);
static HRESULT io4_handle_ioctl(struct irp *irp);
static HRESULT io4_ioctl_get_manufacturer_string(struct irp *irp);
static HRESULT io4_ioctl_get_product_string(struct irp *irp);
static HRESULT io4_async_poll(void *ctx, struct irp *irp);
/* Device node path must contain substring "vid_0ca3" (case-insensitive). */
static const wchar_t io4_path[] = L"$io4\\vid_0ca3";
static const wchar_t io4_manf[] = L"SEGA";
static const wchar_t io4_prod[] =
/* "Product" (N.B. numbers are in hex) */
L"I/O CONTROL BD;" /* Board type */
L"15257;" /* Board number */
L"01;" /* "Mode" (prob. USB vs JVS?) */
L"90;" /* Firmware revision */
L"1831;" /* Firmware checksum */
L"6679A;" /* "Custom chip no" */
L"00;" /* "Config" */
/* "Function" (N.B. all values are in hex) */
L"GOUT=14_" /* General-purpose output */
L"ADIN=8,E_" /* ADC inputs */
L"ROTIN=4_" /* Rotary inputs */
L"COININ=2_" /* Coin inputs */
L"SWIN=2,E_" /* Switch inputs */
L"UQ1=41,6" /* "Unique function 1" */
;
static HANDLE io4_fd;
static struct async io4_async;
static uint8_t io4_system_status;
static const struct io4_ops *io4_ops;
static void *io4_ops_ctx;
HRESULT io4_hook_init(
const struct io4_config *cfg,
const struct io4_ops *ops,
void *ctx)
{
HRESULT hr;
assert(cfg != NULL);
assert(ops != NULL);
if (!cfg->enable) {
return S_FALSE;
}
async_init(&io4_async, NULL);
hr = iohook_open_nul_fd(&io4_fd);
if (FAILED(hr)) {
return hr;
}
io4_ops = ops;
io4_ops_ctx = ctx;
io4_system_status = 0x02; /* idk */
iohook_push_handler(io4_handle_irp);
hr = setupapi_add_phantom_dev(&hid_guid, io4_path);
if (FAILED(hr)) {
return hr;
}
return S_OK;
}
static HRESULT io4_handle_irp(struct irp *irp)
{
assert(irp != NULL);
if (irp->op != IRP_OP_OPEN && irp->fd != io4_fd) {
return iohook_invoke_next(irp);
}
switch (irp->op) {
case IRP_OP_OPEN: return io4_handle_open(irp);
case IRP_OP_CLOSE: return io4_handle_close(irp);
case IRP_OP_READ: return io4_handle_read(irp);
case IRP_OP_WRITE: return io4_handle_write(irp);
case IRP_OP_IOCTL: return io4_handle_ioctl(irp);
default: return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT io4_handle_open(struct irp *irp)
{
if (wcscmp(irp->open_filename, io4_path) != 0) {
return iohook_invoke_next(irp);
}
dprintf("USB I/O: Device opened\n");
irp->fd = io4_fd;
return S_OK;
}
static HRESULT io4_handle_close(struct irp *irp)
{
dprintf("USB I/O: Device closed\n");
return S_OK;
}
static HRESULT io4_handle_read(struct irp *irp)
{
/* The amdaemon USBIO driver will continuously poll the IO until the IO
call returns an async operation in progress. We have to return and then
signal the OVERLAPPED event object "a little bit later" in order to avoid
an infinite loop. */
return async_submit(&io4_async, irp, io4_async_poll);
}
static HRESULT io4_handle_write(struct irp *irp)
{
struct io4_report_out out;
HRESULT hr;
hr = iobuf_read(&irp->write, &out, sizeof(out));
if (FAILED(hr)) {
return hr;
}
if (out.report_id != 0x10) {
dprintf("USB I/O: OUT Report ID is incorrect");
return E_FAIL;
}
switch (out.cmd) {
case IO4_CMD_SET_COMM_TIMEOUT:
dprintf("USB I/O: Set comm timeout\n");
// Ongeki Summer expects the system status to be 0x30 at this point
io4_system_status = 0x30;
return S_OK;
case IO4_CMD_SET_SAMPLING_COUNT:
dprintf("USB I/O: Set sampling count\n");
// Ongeki Summer expects the system status to be 0x30 at this point
io4_system_status = 0x30;
return S_OK;
case IO4_CMD_CLEAR_BOARD_STATUS:
dprintf("USB I/O: Clear board status\n");
io4_system_status = 0x00;
return S_OK;
case IO4_CMD_SET_GENERAL_OUTPUT:
dprintf("USB I/O: GPIO Out\n");
return S_OK;
case IO4_CMD_SET_PWM_OUTPUT:
dprintf("USB I/O: PWM Out\n");
return S_OK;
case IO4_CMD_UPDATE_FIRMWARE:
dprintf("USB I/O: Update firmware..?\n");
return E_FAIL;
case IO4_CMD_UNIMPLEMENTED:
//dprintf("USB I/O: Unimplemented cmd 41\n");
return S_OK;
default:
dprintf("USB I/O: Unknown command %02x\n", out.cmd);
return E_FAIL;
}
}
static HRESULT io4_handle_ioctl(struct irp *irp)
{
switch (irp->ioctl) {
case IOCTL_HID_GET_MANUFACTURER_STRING:
return io4_ioctl_get_manufacturer_string(irp);
case IOCTL_HID_GET_PRODUCT_STRING:
return io4_ioctl_get_product_string(irp);
case IOCTL_HID_GET_INPUT_REPORT:
dprintf("USB I/O: Control IN (untested!!)\n");
return io4_handle_read(irp);
case IOCTL_HID_SET_OUTPUT_REPORT:
dprintf("USB I/O: Control OUT (untested!!)\n");
return io4_handle_write(irp);
default:
dprintf("USB I/O: Unknown ioctl %#08x, write %i read %i\n",
irp->ioctl,
(int) irp->write.nbytes,
(int) irp->read.nbytes);
return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT io4_ioctl_get_manufacturer_string(struct irp *irp)
{
dprintf("USB I/O: Get manufacturer string\n");
if (irp->read.nbytes < sizeof(io4_manf)) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
memcpy(irp->read.bytes, io4_manf, sizeof(io4_manf));
irp->read.pos = sizeof(io4_manf);
return S_OK;
}
static HRESULT io4_ioctl_get_product_string(struct irp *irp)
{
dprintf("USB I/O: Get product string\n");
if (irp->read.nbytes < sizeof(io4_prod)) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
memcpy(irp->read.bytes, io4_prod, sizeof(io4_prod));
irp->read.pos = sizeof(io4_prod);
return S_OK;
}
static HRESULT io4_async_poll(void *ctx, struct irp *irp)
{
struct io4_report_in in;
struct io4_state state;
HRESULT hr;
size_t i;
/* Delay long enough for the instigating thread in amdaemon to be satisfied
that all queued-up reports have been drained. */
Sleep(1);
/* Call into ops to poll the underlying inputs */
memset(&state, 0, sizeof(state));
hr = io4_ops->poll(io4_ops_ctx, &state);
if (FAILED(hr)) {
return hr;
}
/* Construct IN report. Values are all little-endian, unlike JVS. */
memset(&in, 0, sizeof(in));
in.report_id = 0x01;
in.system_status = io4_system_status;
for (i = 0 ; i < 8 ; i++) {
in.adcs[i] = state.adcs[i];
}
for (i = 0 ; i < 4 ; i++) {
in.spinners[i] = state.spinners[i];
}
for (i = 0 ; i < 2 ; i++) {
in.chutes[i] = state.chutes[i];
}
for (i = 0 ; i < 2 ; i++) {
in.buttons[i] = state.buttons[i];
}
return iobuf_write(&irp->read, &in, sizeof(in));
}
-33
View File
@@ -1,33 +0,0 @@
#pragma once
#include <windows.h>
#include <stdint.h>
#include <stdbool.h>
enum {
/* System buttons in button[0] */
IO4_BUTTON_TEST = 1 << 9,
IO4_BUTTON_SERVICE = 1 << 6,
};
struct io4_config {
bool enable;
};
struct io4_state {
uint16_t adcs[8];
uint16_t spinners[4];
uint16_t chutes[2];
uint16_t buttons[2];
};
struct io4_ops {
HRESULT (*poll)(void *ctx, struct io4_state *state);
};
HRESULT io4_hook_init(
const struct io4_config *cfg,
const struct io4_ops *ops,
void *ctx);
+20 -2
View File
@@ -13,6 +13,8 @@
#include "jvs/jvs-cmd.h"
#include "jvs/jvs-util.h"
#include "iccard/nesica.h"
#include "util/dprintf.h"
#include "util/dump.h"
@@ -84,6 +86,8 @@ void k92x0249_init(
k92x0249->addr = 0xFF;
k92x0249->state = IDLE;
k92x0249->ops_ctx = ops_ctx;
nesica_card_populate(&k92x0249->mifare, cfg.serial, 16);
}
struct jvs_node *k92x0249_to_jvs_node(struct k92x0249 *k92x0249)
@@ -411,13 +415,27 @@ static HRESULT k92x0249_cmd_taito_nesica_read(struct k92x0249 *k92x0249, struct
return hr;
}
hr = iobuf_write(resp_buf, card_uid, 8); // AICC: Unused, should be IDm
// Mifare: UID (3 bytes from page 1, 4 bytes from page 2, null byte)
hr = iobuf_write(resp_buf, k92x0249->mifare.pages[0].bytes, 3); // AICC: Unused, should be IDm
if (FAILED(hr)) {
return hr;
}
hr = iobuf_write(resp_buf, k92x0249->mifare.pages[1].bytes, 4); // AICC: Unused, should be IDm
if (FAILED(hr)) {
return hr;
}
hr = iobuf_write_8(resp_buf, 0x00); // AICC: Unused, should be IDm
if (FAILED(hr)) {
return hr;
}
return iobuf_write(resp_buf, cfg.serial, 16); // AICC: SPAD0
// Mifare: sn (pages 5-8)
return iobuf_write(resp_buf, k92x0249->mifare.pages[5].bytes, 16); // AICC: SPAD0
}
static HRESULT k92x0249_cmd_taito_aic_read(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf)
+4
View File
@@ -2,6 +2,8 @@
#include <windows.h>
#include "jvs/jvs-bus.h"
#include "iccard/mifare.h"
#include "iccard/felica.h"
#pragma pack(push,1)
struct k92x0249 {
@@ -9,6 +11,8 @@ struct k92x0249 {
uint8_t state;
uint8_t addr;
void *ops_ctx;
struct mifare_ul mifare;
struct felica felica;
};
struct k92x0249_config {
-12
View File
@@ -22,17 +22,5 @@ board_lib = static_library(
'k92x0249.h',
'k9101258.c',
'k9101258.h',
'io4.c',
'io4.h',
'sg-cmd.c',
'sg-cmd.h',
'sg-frame.c',
'sg-frame.h',
'sg-led.c',
'sg-led.h',
'sg-led-cmd.h',
'sg-nfc.c',
'sg-nfc.h',
'sg-nfc-cmd.h',
],
)
-134
View File
@@ -1,134 +0,0 @@
#include <assert.h>
#include "board/sg-cmd.h"
#include "board/sg-frame.h"
#include "hook/iobuf.h"
#include "util/dprintf.h"
union sg_req_any {
struct sg_req_header req;
uint8_t bytes[256];
};
union sg_res_any {
struct sg_res_header res;
uint8_t bytes[256];
};
static HRESULT sg_req_validate(const void *ptr, size_t nbytes);
static void sg_res_error(
struct sg_res_header *res,
const struct sg_req_header *req);
static HRESULT sg_req_validate(const void *ptr, size_t nbytes)
{
const struct sg_req_header *req;
size_t payload_len;
assert(ptr != NULL);
if (nbytes < sizeof(*req)) {
dprintf("SG Cmd: Request header truncated\n");
return E_FAIL;
}
req = ptr;
if (req->hdr.frame_len != nbytes) {
dprintf("SG Cmd: Frame length mismatch: got %i exp %i\n",
req->hdr.frame_len,
(int) nbytes);
return E_FAIL;
}
payload_len = req->hdr.frame_len - sizeof(*req);
if (req->payload_len != payload_len) {
dprintf("SG Cmd: Payload length mismatch: got %i exp %i\n",
req->payload_len,
(int) payload_len);
return E_FAIL;
}
return S_OK;
}
void sg_req_transact(
struct iobuf *res_frame,
const uint8_t *req_bytes,
size_t req_nbytes,
sg_dispatch_fn_t dispatch,
void *ctx)
{
struct iobuf req_span;
union sg_req_any req;
union sg_res_any res;
HRESULT hr;
assert(res_frame != NULL);
assert(req_bytes != NULL);
assert(dispatch != NULL);
req_span.bytes = req.bytes;
req_span.nbytes = sizeof(req.bytes);
req_span.pos = 0;
hr = sg_frame_decode(&req_span, req_bytes, req_nbytes);
if (FAILED(hr)) {
return;
}
hr = sg_req_validate(req.bytes, req_span.pos);
if (FAILED(hr)) {
return;
}
hr = dispatch(ctx, &req, &res);
if (hr != S_FALSE) {
if (FAILED(hr)) {
sg_res_error(&res.res, &req.req);
}
sg_frame_encode(res_frame, res.bytes, res.res.hdr.frame_len);
}
}
void sg_res_init(
struct sg_res_header *res,
const struct sg_req_header *req,
size_t payload_len)
{
assert(res != NULL);
assert(req != NULL);
res->hdr.frame_len = sizeof(*res) + payload_len;
res->hdr.addr = req->hdr.addr;
res->hdr.seq_no = req->hdr.seq_no;
res->hdr.cmd = req->hdr.cmd;
res->status = 0;
res->payload_len = payload_len;
}
static void sg_res_error(
struct sg_res_header *res,
const struct sg_req_header *req)
{
assert(res != NULL);
assert(req != NULL);
res->hdr.frame_len = sizeof(*res);
res->hdr.addr = req->hdr.addr;
res->hdr.seq_no = req->hdr.seq_no;
res->hdr.cmd = req->hdr.cmd;
res->status = 1;
res->payload_len = 0;
}
-43
View File
@@ -1,43 +0,0 @@
#pragma once
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
#include "hook/iobuf.h"
struct sg_header {
uint8_t frame_len;
uint8_t addr;
uint8_t seq_no;
uint8_t cmd;
};
struct sg_req_header {
struct sg_header hdr;
uint8_t payload_len;
};
struct sg_res_header {
struct sg_header hdr;
uint8_t status;
uint8_t payload_len;
};
typedef HRESULT (*sg_dispatch_fn_t)(
void *ctx,
const void *req,
void *res);
void sg_req_transact(
struct iobuf *res_frame,
const uint8_t *req_bytes,
size_t req_nbytes,
sg_dispatch_fn_t dispatch,
void *ctx);
void sg_res_init(
struct sg_res_header *res,
const struct sg_req_header *req,
size_t payload_len);
-165
View File
@@ -1,165 +0,0 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "board/sg-frame.h"
#include "hook/iobuf.h"
#include "util/dprintf.h"
static HRESULT sg_frame_accept(struct iobuf *dest);
static HRESULT sg_frame_encode_byte(struct iobuf *dest, uint8_t byte);
/* Frame structure:
[0] Sync byte (0xE0)
[1] Frame size (including self)
[2] Address
[3] Sequence no
... Body
[n] Checksum: Sum of all non-framing bytes
Byte stuffing:
0xD0 is an escape byte. Un-escape the subsequent byte by adding 1. */
static HRESULT sg_frame_accept(struct iobuf *dest)
{
uint8_t checksum;
size_t i;
if (dest->pos < 1 || dest->pos != dest->bytes[0] + 1) {
dprintf("SG Frame: Size mismatch\n");
return S_FALSE;
}
checksum = 0;
for (i = 0 ; i < dest->pos - 1 ; i++) {
checksum += dest->bytes[i];
}
if (checksum != dest->bytes[dest->pos - 1]) {
dprintf("SG Frame: Checksum mismatch\n");
return HRESULT_FROM_WIN32(ERROR_CRC);
}
/* Discard checksum */
dest->pos--;
return S_OK;
}
HRESULT sg_frame_decode(struct iobuf *dest, const uint8_t *bytes, size_t nbytes)
{
uint8_t byte;
size_t i;
assert(dest != NULL);
assert(dest->bytes != NULL || dest->nbytes == 0);
assert(dest->pos <= dest->nbytes);
assert(bytes != NULL);
if (nbytes < 1 || bytes[0] != 0xE0) {
dprintf("SG Frame: Bad sync\n");
return E_FAIL;
}
dest->pos = 0;
i = 1;
while (i < nbytes) {
if (dest->pos >= dest->nbytes) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
byte = bytes[i++];
if (byte == 0xE0) {
dprintf("SG Frame: Unescaped sync\n");
return E_FAIL;
} else if (byte == 0xD0) {
if (i >= nbytes) {
dprintf("SG Frame: Trailing escape\n");
return E_FAIL;
}
byte = bytes[i++];
dest->bytes[dest->pos++] = byte + 1;
} else {
dest->bytes[dest->pos++] = byte;
}
}
return sg_frame_accept(dest);
}
HRESULT sg_frame_encode(
struct iobuf *dest,
const void *ptr,
size_t nbytes)
{
const uint8_t *src;
uint8_t checksum;
uint8_t byte;
size_t i;
HRESULT hr;
assert(dest != NULL);
assert(dest->bytes != NULL || dest->nbytes == 0);
assert(dest->pos <= dest->nbytes);
assert(ptr != NULL);
src = ptr;
assert(nbytes != 0 && src[0] == nbytes);
if (dest->pos >= dest->nbytes) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
dest->bytes[dest->pos++] = 0xE0;
checksum = 0;
for (i = 0 ; i < nbytes ; i++) {
byte = src[i];
checksum += byte;
hr = sg_frame_encode_byte(dest, byte);
if (FAILED(hr)) {
return hr;
}
}
return sg_frame_encode_byte(dest, checksum);
}
static HRESULT sg_frame_encode_byte(struct iobuf *dest, uint8_t byte)
{
if (byte == 0xD0 || byte == 0xE0) {
if (dest->pos + 2 > dest->nbytes) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
dest->bytes[dest->pos++] = 0xD0;
dest->bytes[dest->pos++] = byte - 1;
} else {
if (dest->pos + 1 > dest->nbytes) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
dest->bytes[dest->pos++] = byte;
}
return S_OK;
}
-15
View File
@@ -1,15 +0,0 @@
#pragma once
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
#include "hook/iobuf.h"
HRESULT sg_frame_decode(
struct iobuf *dest,
const uint8_t *bytes,
size_t nbytes);
HRESULT sg_frame_encode(struct iobuf *dest, const void *ptr, size_t nbytes);
-39
View File
@@ -1,39 +0,0 @@
#pragma once
#include <stdint.h>
#include "board/sg-cmd.h"
enum {
SG_RGB_CMD_SET_COLOR = 0x81,
SG_RGB_CMD_RESET = 0xF5,
SG_RGB_CMD_GET_INFO = 0xF0,
};
struct sg_led_res_reset {
struct sg_res_header res;
uint8_t payload;
};
struct sg_led_res_get_info {
struct sg_res_header res;
uint8_t payload[9];
};
struct sg_led_req_set_color {
struct sg_req_header req;
uint8_t payload[3];
};
union sg_led_req_any {
uint8_t bytes[256];
struct sg_req_header simple;
struct sg_led_req_set_color set_color;
};
union sg_led_res_any {
uint8_t bytes[256];
struct sg_res_header simple;
struct sg_led_res_reset reset;
struct sg_led_res_get_info get_info;
};
-178
View File
@@ -1,178 +0,0 @@
#include <windows.h>
#include <assert.h>
#include "board/sg-cmd.h"
#include "board/sg-led.h"
#include "board/sg-led-cmd.h"
#include "util/dprintf.h"
static HRESULT sg_led_dispatch(
void *ctx,
const void *v_req,
void *v_res);
static HRESULT sg_led_cmd_reset(
const struct sg_led *led,
const struct sg_req_header *req,
struct sg_led_res_reset *res);
static HRESULT sg_led_cmd_get_info(
const struct sg_led *led,
const struct sg_req_header *req,
struct sg_led_res_get_info *res);
static HRESULT sg_led_cmd_set_color(
const struct sg_led *led,
const struct sg_led_req_set_color *req);
static const uint8_t sg_led_info[] = {
'1', '5', '0', '8', '4', 0xFF, 0x10, 0x00, 0x12,
};
void sg_led_init(
struct sg_led *led,
uint8_t addr,
const struct sg_led_ops *ops,
void *ctx)
{
assert(led != NULL);
assert(ops != NULL);
led->ops = ops;
led->ops_ctx = ctx;
led->addr = addr;
}
void sg_led_transact(
struct sg_led *led,
struct iobuf *res_frame,
const void *req_bytes,
size_t req_nbytes)
{
assert(led != NULL);
assert(res_frame != NULL);
assert(req_bytes != NULL);
sg_req_transact(res_frame, req_bytes, req_nbytes, sg_led_dispatch, led);
}
#ifdef NDEBUG
#define sg_led_dprintfv(led, fmt, ap)
#define sg_led_dprintf(led, fmt, ...)
#else
static void sg_led_dprintfv(
const struct sg_led *led,
const char *fmt,
va_list ap)
{
dprintf("RGB LED %02x: ", led->addr);
dprintfv(fmt, ap);
}
static void sg_led_dprintf(
const struct sg_led *led,
const char *fmt,
...)
{
va_list ap;
va_start(ap, fmt);
sg_led_dprintfv(led, fmt, ap);
va_end(ap);
}
#endif
static HRESULT sg_led_dispatch(
void *ctx,
const void *v_req,
void *v_res)
{
const struct sg_led *led;
const union sg_led_req_any *req;
union sg_led_res_any *res;
led = ctx;
req = v_req;
res = v_res;
if (req->simple.hdr.addr != led->addr) {
/* Not addressed to us, don't send a response */
return S_FALSE;
}
switch (req->simple.hdr.cmd) {
case SG_RGB_CMD_RESET:
return sg_led_cmd_reset(led, &req->simple, &res->reset);
case SG_RGB_CMD_GET_INFO:
return sg_led_cmd_get_info(led, &req->simple, &res->get_info);
case SG_RGB_CMD_SET_COLOR:
return sg_led_cmd_set_color(led, &req->set_color);
default:
sg_led_dprintf(led, "Unimpl command %02x\n", req->simple.hdr.cmd);
return E_NOTIMPL;
}
}
static HRESULT sg_led_cmd_reset(
const struct sg_led *led,
const struct sg_req_header *req,
struct sg_led_res_reset *res)
{
HRESULT hr;
sg_led_dprintf(led, "Reset\n");
sg_res_init(&res->res, req, sizeof(res->payload));
res->payload = 0;
if (led->ops->reset != NULL) {
hr = led->ops->reset(led->ops_ctx);
} else {
hr = S_OK;
}
if (FAILED(hr)) {
sg_led_dprintf(led, "led->ops->reset: Error %x\n", hr);
return hr;
}
return S_OK;
}
static HRESULT sg_led_cmd_get_info(
const struct sg_led *led,
const struct sg_req_header *req,
struct sg_led_res_get_info *res)
{
sg_led_dprintf(led, "Get info\n");
sg_res_init(&res->res, req, sizeof(res->payload));
memcpy(res->payload, sg_led_info, sizeof(sg_led_info));
return S_OK;
}
static HRESULT sg_led_cmd_set_color(
const struct sg_led *led,
const struct sg_led_req_set_color *req)
{
if (req->req.payload_len != sizeof(req->payload)) {
sg_led_dprintf(led, "%s: Payload size is incorrect\n", __func__);
goto fail;
}
led->ops->set_color(
led->ops_ctx,
req->payload[0],
req->payload[1],
req->payload[2]);
fail:
/* No response */
return S_FALSE;
}
-30
View File
@@ -1,30 +0,0 @@
#pragma once
#include <windows.h>
#include <stdint.h>
#include "hook/iobuf.h"
struct sg_led_ops {
HRESULT (*reset)(void *ctx);
void (*set_color)(void *ctx, uint8_t r, uint8_t g, uint8_t b);
};
struct sg_led {
const struct sg_led_ops *ops;
void *ops_ctx;
uint8_t addr;
};
void sg_led_init(
struct sg_led *led,
uint8_t addr,
const struct sg_led_ops *ops,
void *ctx);
void sg_led_transact(
struct sg_led *led,
struct iobuf *res_frame,
const void *req_bytes,
size_t req_nbytes);
-115
View File
@@ -1,115 +0,0 @@
#pragma once
#include <stdint.h>
#pragma pack(push, 1)
enum {
SG_NFC_CMD_GET_FW_VERSION = 0x30,
SG_NFC_CMD_GET_HW_VERSION = 0x32,
SG_NFC_CMD_RADIO_ON = 0x40,
SG_NFC_CMD_RADIO_OFF = 0x41,
SG_NFC_CMD_POLL = 0x42,
SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43,
SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x50,
SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52,
SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x54,
SG_NFC_CMD_MIFARE_AUTHENTICATE = 0x55, /* guess based on time sent */
SG_NFC_CMD_RESET = 0x62,
SG_NFC_CMD_FELICA_ENCAP = 0x71,
};
struct sg_nfc_res_get_fw_version {
struct sg_res_header res;
char version[23];
};
struct sg_nfc_res_get_hw_version {
struct sg_res_header res;
char version[23];
};
struct sg_nfc_req_mifare_set_key {
struct sg_req_header req;
uint8_t key_a[6];
};
struct sg_nfc_req_mifare_50 {
struct sg_req_header req;
uint8_t payload[6];
};
struct sg_nfc_req_poll_40 {
struct sg_req_header req;
uint8_t payload;
};
struct sg_nfc_poll_mifare {
uint8_t type;
uint8_t id_len;
uint32_t uid;
};
struct sg_nfc_poll_felica {
uint8_t type;
uint8_t id_len;
uint64_t IDm;
uint64_t PMm;
};
struct sg_nfc_res_poll {
struct sg_res_header res;
uint8_t count;
uint8_t payload[250];
};
struct sg_nfc_req_mifare_select_tag {
struct sg_res_header res;
uint32_t uid;
};
struct sg_nfc_req_mifare_read_block {
struct sg_req_header req;
struct {
uint32_t uid;
uint8_t block_no;
} payload;
};
struct sg_nfc_res_mifare_read_block {
struct sg_res_header res;
uint8_t block[16];
};
struct sg_nfc_req_felica_encap {
struct sg_req_header req;
uint64_t IDm;
uint8_t payload[243];
};
struct sg_nfc_res_felica_encap {
struct sg_res_header res;
uint8_t payload[250];
};
union sg_nfc_req_any {
uint8_t bytes[256];
struct sg_req_header simple;
struct sg_nfc_req_mifare_set_key mifare_set_key;
struct sg_nfc_req_mifare_read_block mifare_read_block;
struct sg_nfc_req_mifare_50 mifare_50;
struct sg_nfc_req_poll_40 poll_40;
struct sg_nfc_req_felica_encap felica_encap;
};
union sg_nfc_res_any {
uint8_t bytes[256];
struct sg_res_header simple;
struct sg_nfc_res_get_fw_version get_fw_version;
struct sg_nfc_res_get_hw_version get_hw_version;
struct sg_nfc_res_poll poll;
struct sg_nfc_res_mifare_read_block mifare_read_block;
struct sg_nfc_res_felica_encap felica_encap;
};
#pragma pack(pop)
-434
View File
@@ -1,434 +0,0 @@
#include <windows.h>
#include <assert.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "board/sg-cmd.h"
#include "board/sg-nfc.h"
#include "board/sg-nfc-cmd.h"
#include "iccard/nesica.h"
#include "iccard/felica.h"
#include "util/dprintf.h"
#include "util/dump.h"
static HRESULT sg_nfc_dispatch(
void *ctx,
const void *v_req,
void *v_res);
static HRESULT sg_nfc_cmd_reset(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res);
static HRESULT sg_nfc_cmd_get_fw_version(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_nfc_res_get_fw_version *res);
static HRESULT sg_nfc_cmd_get_hw_version(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_nfc_res_get_hw_version *res);
static HRESULT sg_nfc_cmd_poll(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_nfc_res_poll *res);
static HRESULT sg_nfc_poll_aime(
struct sg_nfc *nfc,
struct sg_nfc_poll_mifare *mifare);
static HRESULT sg_nfc_poll_felica(
struct sg_nfc *nfc,
struct sg_nfc_poll_felica *felica);
static HRESULT sg_nfc_cmd_mifare_read_block(
struct sg_nfc *nfc,
const struct sg_nfc_req_mifare_read_block *req,
struct sg_nfc_res_mifare_read_block *res);
static HRESULT sg_nfc_cmd_felica_encap(
struct sg_nfc *nfc,
const struct sg_nfc_req_felica_encap *req,
struct sg_nfc_res_felica_encap *res);
static HRESULT sg_nfc_cmd_dummy(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res);
void sg_nfc_init(
struct sg_nfc *nfc,
uint8_t addr,
const struct sg_nfc_ops *ops,
void *ops_ctx)
{
assert(nfc != NULL);
assert(ops != NULL);
nfc->ops = ops;
nfc->ops_ctx = ops_ctx;
nfc->addr = addr;
}
#ifdef NDEBUG
#define sg_nfc_dprintfv(nfc, fmt, ap)
#define sg_nfc_dprintf(nfc, fmt, ...)
#else
static void sg_nfc_dprintfv(
const struct sg_nfc *nfc,
const char *fmt,
va_list ap)
{
dprintf("NFC %02x: ", nfc->addr);
dprintfv(fmt, ap);
}
static void sg_nfc_dprintf(
const struct sg_nfc *nfc,
const char *fmt,
...)
{
va_list ap;
va_start(ap, fmt);
sg_nfc_dprintfv(nfc, fmt, ap);
va_end(ap);
}
#endif
void sg_nfc_transact(
struct sg_nfc *nfc,
struct iobuf *res_frame,
const void *req_bytes,
size_t req_nbytes)
{
assert(nfc != NULL);
assert(res_frame != NULL);
assert(req_bytes != NULL);
sg_req_transact(res_frame, req_bytes, req_nbytes, sg_nfc_dispatch, nfc);
}
static HRESULT sg_nfc_dispatch(
void *ctx,
const void *v_req,
void *v_res)
{
struct sg_nfc *nfc;
const union sg_nfc_req_any *req;
union sg_nfc_res_any *res;
nfc = ctx;
req = v_req;
res = v_res;
if (req->simple.hdr.addr != nfc->addr) {
/* Not addressed to us, don't send a response */
return S_FALSE;
}
switch (req->simple.hdr.cmd) {
case SG_NFC_CMD_RESET:
return sg_nfc_cmd_reset(nfc, &req->simple, &res->simple);
case SG_NFC_CMD_GET_FW_VERSION:
return sg_nfc_cmd_get_fw_version(
nfc,
&req->simple,
&res->get_fw_version);
case SG_NFC_CMD_GET_HW_VERSION:
return sg_nfc_cmd_get_hw_version(
nfc,
&req->simple,
&res->get_hw_version);
case SG_NFC_CMD_POLL:
return sg_nfc_cmd_poll(
nfc,
&req->simple,
&res->poll);
case SG_NFC_CMD_MIFARE_READ_BLOCK:
return sg_nfc_cmd_mifare_read_block(
nfc,
&req->mifare_read_block,
&res->mifare_read_block);
case SG_NFC_CMD_FELICA_ENCAP:
return sg_nfc_cmd_felica_encap(
nfc,
&req->felica_encap,
&res->felica_encap);
case SG_NFC_CMD_MIFARE_AUTHENTICATE:
case SG_NFC_CMD_MIFARE_SELECT_TAG:
case SG_NFC_CMD_MIFARE_SET_KEY_AIME:
case SG_NFC_CMD_MIFARE_SET_KEY_BANA:
case SG_NFC_CMD_RADIO_ON:
case SG_NFC_CMD_RADIO_OFF:
return sg_nfc_cmd_dummy(nfc, &req->simple, &res->simple);
default:
sg_nfc_dprintf(nfc, "Unimpl command %02x\n", req->simple.hdr.cmd);
return E_NOTIMPL;
}
}
static HRESULT sg_nfc_cmd_reset(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res)
{
sg_nfc_dprintf(nfc, "Reset\n");
sg_res_init(res, req, 0);
res->status = 3;
return S_OK;
}
static HRESULT sg_nfc_cmd_get_fw_version(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_nfc_res_get_fw_version *res)
{
/* Dest version is not NUL terminated, this is intentional */
sg_res_init(&res->res, req, sizeof(res->version));
memcpy(res->version, "TN32MSEC003S F/W Ver1.2E", sizeof(res->version));
return S_OK;
}
static HRESULT sg_nfc_cmd_get_hw_version(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_nfc_res_get_hw_version *res)
{
/* Dest version is not NUL terminated, this is intentional */
sg_res_init(&res->res, req, sizeof(res->version));
memcpy(res->version, "TN32MSEC003S H/W Ver3.0J", sizeof(res->version));
return S_OK;
}
static HRESULT sg_nfc_cmd_poll(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_nfc_res_poll *res)
{
struct sg_nfc_poll_mifare mifare;
struct sg_nfc_poll_felica felica;
HRESULT hr;
hr = nfc->ops->poll(nfc->ops_ctx);
if (FAILED(hr)) {
return hr;
}
hr = sg_nfc_poll_felica(nfc, &felica);
if (SUCCEEDED(hr) && hr != S_FALSE) {
sg_res_init(&res->res, req, 1 + sizeof(felica));
memcpy(res->payload, &felica, sizeof(felica));
res->count = 1;
return S_OK;
}
hr = sg_nfc_poll_aime(nfc, &mifare);
if (SUCCEEDED(hr) && hr != S_FALSE) {
sg_res_init(&res->res, req, 1 + sizeof(mifare));
memcpy(res->payload, &mifare, sizeof(mifare));
res->count = 1;
return S_OK;
}
sg_res_init(&res->res, req, 1);
res->count = 0;
return S_OK;
}
static HRESULT sg_nfc_poll_aime(
struct sg_nfc *nfc,
struct sg_nfc_poll_mifare *mifare)
{
uint8_t luid[10];
HRESULT hr;
/* Call backend */
if (nfc->ops->get_aime_id != NULL) {
hr = nfc->ops->get_aime_id(nfc->ops_ctx, luid, sizeof(luid));
} else {
hr = S_FALSE;
}
if (FAILED(hr) || hr == S_FALSE) {
return hr;
}
sg_nfc_dprintf(nfc, "AiMe card is present\n");
/* Construct response (use an arbitrary UID) */
mifare->type = 0x10;
mifare->id_len = sizeof(mifare->uid);
mifare->uid = _byteswap_ulong(0x01020304);
/* Initialize MIFARE IC emulator */
hr = aime_card_populate(&nfc->mifare, luid, sizeof(luid));
if (FAILED(hr)) {
return hr;
}
return S_OK;
}
static HRESULT sg_nfc_poll_felica(
struct sg_nfc *nfc,
struct sg_nfc_poll_felica *felica)
{
uint64_t IDm;
HRESULT hr;
/* Call backend */
if (nfc->ops->get_felica_id != NULL) {
hr = nfc->ops->get_felica_id(nfc->ops_ctx, &IDm);
} else {
hr = S_FALSE;
}
if (FAILED(hr) || hr == S_FALSE) {
return hr;
}
sg_nfc_dprintf(nfc, "FeliCa card is present\n");
/* Construct poll response */
felica->type = 0x20;
felica->id_len = sizeof(felica->IDm) + sizeof(felica->PMm);
felica->IDm = _byteswap_uint64(IDm);
felica->PMm = _byteswap_uint64(felica_get_generic_PMm());
/* Initialize FeliCa IC emulator */
nfc->felica.IDm = IDm;
nfc->felica.PMm = felica_get_generic_PMm();
nfc->felica.system_code = 0x0000;
return S_OK;
}
static HRESULT sg_nfc_cmd_mifare_read_block(
struct sg_nfc *nfc,
const struct sg_nfc_req_mifare_read_block *req,
struct sg_nfc_res_mifare_read_block *res)
{
uint32_t uid;
if (req->req.payload_len != sizeof(req->payload)) {
sg_nfc_dprintf(nfc, "%s: Payload size is incorrect\n", __func__);
return E_FAIL;
}
uid = _byteswap_ulong(req->payload.uid);
sg_nfc_dprintf(nfc, "Read uid %08x block %i\n", uid, req->payload.block_no);
if (req->payload.block_no > 3) {
sg_nfc_dprintf(nfc, "MIFARE block number out of range\n");
return E_FAIL;
}
sg_res_init(&res->res, &req->req, sizeof(res->block));
memcpy( res->block,
nfc->mifare.sectors[0].blocks[req->payload.block_no].bytes,
sizeof(res->block));
return S_OK;
}
static HRESULT sg_nfc_cmd_felica_encap(
struct sg_nfc *nfc,
const struct sg_nfc_req_felica_encap *req,
struct sg_nfc_res_felica_encap *res)
{
struct const_iobuf f_req;
struct iobuf f_res;
HRESULT hr;
/* First byte of encapsulated request and response is a length byte
(inclusive of itself). The FeliCa emulator expects its caller to handle
that length byte on its behalf (we adopt the convention that the length
byte is part of the FeliCa protocol's framing layer). */
if (req->req.payload_len != 8 + req->payload[0]) {
sg_nfc_dprintf(
nfc,
"FeliCa encap payload length mismatch: sg %i != felica %i + 8",
req->req.payload_len,
req->payload[0]);
return E_FAIL;
}
f_req.bytes = req->payload;
f_req.nbytes = req->payload[0];
f_req.pos = 1;
f_res.bytes = res->payload;
f_res.nbytes = sizeof(res->payload);
f_res.pos = 1;
#if 0
dprintf("FELICA OUTBOUND:\n");
dump_const_iobuf(&f_req);
#endif
hr = felica_transact(&nfc->felica, &f_req, &f_res);
if (FAILED(hr)) {
return hr;
}
sg_res_init(&res->res, &req->req, f_res.pos);
res->payload[0] = f_res.pos;
#if 0
dprintf("FELICA INBOUND:\n");
dump_iobuf(&f_res);
#endif
return S_OK;
}
static HRESULT sg_nfc_cmd_dummy(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res)
{
sg_res_init(res, req, 0);
return S_OK;
}
-39
View File
@@ -1,39 +0,0 @@
#pragma once
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
#include "hook/iobuf.h"
#include "iccard/felica.h"
#include "iccard/mifare.h"
struct sg_nfc_ops {
HRESULT (*poll)(void *ctx);
HRESULT (*get_aime_id)(void *ctx, uint8_t *luid, size_t nbytes);
HRESULT (*get_felica_id)(void *ctx, uint64_t *IDm);
// TODO Banapass, AmuseIC
};
struct sg_nfc {
const struct sg_nfc_ops *ops;
void *ops_ctx;
uint8_t addr;
struct felica felica;
struct mifare mifare;
};
void sg_nfc_init(
struct sg_nfc *nfc,
uint8_t addr,
const struct sg_nfc_ops *ops,
void *ops_ctx);
void sg_nfc_transact(
struct sg_nfc *nfc,
struct iobuf *res_frame,
const void *req_bytes,
size_t req_nbytes);
-2
View File
@@ -2,8 +2,6 @@
#include <stdlib.h>
#include <stdio.h>
#include "board/io4.h"
#include "hook/process.h"
#include "hooklib/serial.h"
+8
View File
@@ -14,6 +14,7 @@ static uint16_t coins;
static uint16_t services;
static void gc_fastio_digital_read(void *ctx, uint32_t *out);
static void gc_fastio_analog_read(void* ctx, uint8_t num, uint32_t *out);
static void gc_fastio_coin_read(void *ctx, uint8_t slot_no, uint32_t *out);
HRESULT gc_fastio_init(struct fastio_node *out)
@@ -24,6 +25,7 @@ HRESULT gc_fastio_init(struct fastio_node *out)
out->digital_in = gc_fastio_digital_read;
out->coins_in = gc_fastio_coin_read;
out->analog_in = gc_fastio_analog_read;
dprintf("Gc Nesica Fastio: Init\n");
@@ -116,3 +118,9 @@ static void gc_fastio_coin_read(void *ctx, uint8_t slot_no, uint32_t *out)
*out += coin;
*out += service;
}
static void gc_fastio_analog_read(void* ctx, uint8_t num, uint32_t *out)
{
if (num == 2) { *out = 0xff; }
else { *out = 0x00; }
}
+1 -1
View File
@@ -30,4 +30,4 @@ void gc_io_config_load(struct gc_input_config *cfg, const wchar_t *filename)
cfg->stick_r_right = GetPrivateProfileIntW(L"deck", L"right_stick_right", 'L', filename);
cfg->stick_r_down = GetPrivateProfileIntW(L"deck", L"right_stick_down", 'K', filename);
cfg->stick_r_left = GetPrivateProfileIntW(L"deck", L"right_stick_left", 'J', filename);
}
}
+1 -1
View File
@@ -28,4 +28,4 @@ struct gc_input_config {
};
#pragma pack(pop)
void gc_io_config_load(struct gc_input_config *cfg, const wchar_t *filename);
void gc_io_config_load(struct gc_input_config *cfg, const wchar_t *filename);
+1 -1
View File
@@ -56,4 +56,4 @@ HRESULT gc_io_init(void);
void gc_io_get_btns(uint8_t *btn, uint8_t *stick);
void gc_io_read_coin_counter(uint16_t *coins, uint16_t *services);
void gc_io_read_coin_counter(uint16_t *coins, uint16_t *services);
+8
View File
@@ -15,6 +15,14 @@ struct mifare {
struct mifare_sector sectors[16];
};
struct mifare_ul_page {
uint8_t bytes[4];
};
struct mifare_ul {
struct mifare_ul_page pages[16];
};
struct nesica_mifare {
uint8_t uid[7];
char nesica_id[16];
+38 -13
View File
@@ -7,8 +7,8 @@
#include "util/dprintf.h"
HRESULT aime_card_populate(
struct mifare *mifare,
HRESULT nesica_card_populate(
struct mifare_ul *mifare,
const uint8_t *card_sn,
size_t nbytes)
{
@@ -18,7 +18,7 @@ HRESULT aime_card_populate(
assert(mifare != NULL);
assert(card_sn != NULL);
memset(mifare, 0, sizeof(*mifare));
memset(mifare, 0xFF, sizeof(*mifare));
if (nbytes != 16) {
dprintf("Nesica IC: Card Serial must be 16 characters\n");
@@ -26,19 +26,44 @@ HRESULT aime_card_populate(
return E_INVALIDARG;
}
for (int i = 0; i < 16; i++) {
mifare->sectors[0].blocks[0].bytes[i] = i;
}
// page0: first 3 bytes of the UID, BCC0
// page1: rest of the UID
// page2: BCC1, INT, LOCK0+1
// page3: 4 one-time programmable bytes
// page4: "T053" (T<3 numbers of unknown purpose>)
// page5-8: 16-byte ascii nesica ID
// page9-f: FF
memset(mifare->sectors[0].blocks[2].bytes, 0xff, 16);
memset(mifare->sectors[0].blocks[3].bytes, 0xff, 16);
// https://www.nxp.com/docs/en/data-sheet/MF0ICU2.pdf
// BCC0 is CT (0x88) ^ UIC[0] ^ UIC[1] ^ UIC[2]
// BCC1 is UIC[3] ^ UIC[4] ^ UIC[5] ^ UIC[6]
// Lock bits signal which parts of the card are write-locked
// On real blue nesicas, OTP and pages 4-8 inclusive are locked (0xF8 0x01)
// Internal is "reserved for internal data" and observed to be 0x48
// OTP bytes are impl specific, observed to be 0x23 0x21 0x54 0x55 on sample card (#!TU)
mifare->sectors[0].blocks[0].bytes[14] = 'T';
mifare->sectors[0].blocks[0].bytes[15] = 'U';
// UID of 00010203040506 with BCC0 8B and BCC1 04
// TODO: User-setable UID?
mifare->pages[0].bytes[0] = 0x00;
mifare->pages[0].bytes[1] = 0x01;
mifare->pages[0].bytes[2] = 0x02;
mifare->pages[0].bytes[3] = 0x8B;
mifare->pages[1].bytes[0] = 0x03;
mifare->pages[1].bytes[1] = 0x04;
mifare->pages[1].bytes[2] = 0x05;
mifare->pages[1].bytes[3] = 0x06;
mifare->pages[2].bytes[0] = 0x04;
memcpy_s(mifare->sectors[0].blocks[1].bytes, 4, (uint8_t *)"T053", 4);
memcpy_s(mifare->sectors[0].blocks[1].bytes + 4, 12, card_sn, 12);
memcpy_s(mifare->sectors[0].blocks[2].bytes, 16, card_sn + 12, 4);
// INT + lock bits
mifare->pages[2].bytes[1] = 0x48;
mifare->pages[2].bytes[2] = 0xF8;
mifare->pages[2].bytes[3] = 0x01;
memcpy_s(mifare->pages[3].bytes, 4, (uint8_t *)"#!TU", 4); // OTP
memcpy_s(mifare->pages[4].bytes, 4, (uint8_t *)"T053", 4); // UID header?
memcpy_s(mifare->pages[5].bytes, 16, card_sn, 16); // UID, should clobber pages 5-8 safely
// The rest of the card was set to 0xFF above, so we're done here
return S_OK;
}
+2 -2
View File
@@ -7,7 +7,7 @@
#include "iccard/mifare.h"
HRESULT aime_card_populate(
struct mifare *mifare,
HRESULT nesica_card_populate(
struct mifare_ul *mifare,
const uint8_t *luid,
size_t nbytes);
+2 -2
View File
@@ -312,6 +312,7 @@ static int hook_iDmacDrvRegisterRead(HANDLE a1, DWORD register_id, DWORD* regist
*register_val = 0;
*err = 0;
EnterCriticalSection(&idmac_critsec);
switch (register_id) {
case 0x0400: *register_val = 0x00010201; break; // DMA card ID
@@ -321,9 +322,7 @@ static int hook_iDmacDrvRegisterRead(HANDLE a1, DWORD register_id, DWORD* regist
case 0x4004: *register_val = 0x00FF0000; break; // Sub Status
case 0x4120: // Main Buttons
EnterCriticalSection(&idmac_critsec);
fastio_digital_read(NULL, 0, (uint32_t *)register_val);
LeaveCriticalSection(&idmac_critsec);
break;
case 0x4124: // Analog 1
@@ -386,6 +385,7 @@ static int hook_iDmacDrvRegisterRead(HANDLE a1, DWORD register_id, DWORD* regist
dprintf("iDmac: Requested read register %04lX\n", register_id);
break;
}
LeaveCriticalSection(&idmac_critsec);
return 0;
}
-2
View File
@@ -2,8 +2,6 @@
#include <stdlib.h>
#include <stdio.h>
#include "board/io4.h"
#include "hook/process.h"
#include "hooklib/serial.h"