forked from Dniel97/segatools
iccard/felica.c: Add initial FeliCa IC emulator
This commit is contained in:
parent
568baa3841
commit
a09843cbd6
192
iccard/felica.c
Normal file
192
iccard/felica.c
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "hook/iobuf.h"
|
||||||
|
|
||||||
|
#include "iccard/felica.h"
|
||||||
|
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
#include "util/dump.h"
|
||||||
|
|
||||||
|
static HRESULT felica_cmd_poll(
|
||||||
|
struct felica *f,
|
||||||
|
struct const_iobuf *req,
|
||||||
|
struct iobuf *res);
|
||||||
|
|
||||||
|
static HRESULT felica_cmd_get_system_code(
|
||||||
|
struct felica *f,
|
||||||
|
struct const_iobuf *req,
|
||||||
|
struct iobuf *res);
|
||||||
|
|
||||||
|
static HRESULT felica_cmd_nda_a4(
|
||||||
|
struct felica *f,
|
||||||
|
struct const_iobuf *req,
|
||||||
|
struct iobuf *res);
|
||||||
|
|
||||||
|
uint64_t felica_get_generic_PMm(void)
|
||||||
|
{
|
||||||
|
/* A FeliCa PMm contains low-level protocol timing information for
|
||||||
|
communicating with a particular IC card. The exact values are not
|
||||||
|
particularly important for our purposes, so we'll just return a hard-
|
||||||
|
coded PMm. This was taken from a SuiCa train pass I bought in Japan. */
|
||||||
|
|
||||||
|
return 0x053143454682B7FFULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT felica_transact(
|
||||||
|
struct felica *f,
|
||||||
|
struct const_iobuf *req,
|
||||||
|
struct iobuf *res)
|
||||||
|
{
|
||||||
|
uint64_t IDm;
|
||||||
|
uint8_t code;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
assert(f != NULL);
|
||||||
|
assert(req != NULL);
|
||||||
|
assert(res != NULL);
|
||||||
|
|
||||||
|
hr = iobuf_read_8(req, &code);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = iobuf_write_8(res, code + 1);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (code != FELICA_CMD_POLL) {
|
||||||
|
hr = iobuf_read_be64(req, &IDm);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IDm != f->IDm) {
|
||||||
|
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = iobuf_write_be64(res, IDm);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (code) {
|
||||||
|
case FELICA_CMD_POLL:
|
||||||
|
return felica_cmd_poll(f, req, res);
|
||||||
|
|
||||||
|
case FELICA_CMD_GET_SYSTEM_CODE:
|
||||||
|
return felica_cmd_get_system_code(f, req, res);
|
||||||
|
|
||||||
|
case FELICA_CMD_NDA_A4:
|
||||||
|
return felica_cmd_nda_a4(f, req, res);
|
||||||
|
|
||||||
|
default:
|
||||||
|
dprintf("FeliCa: Unimplemented command %02x, payload:\n", code);
|
||||||
|
dump_const_iobuf(req);
|
||||||
|
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT felica_cmd_poll(
|
||||||
|
struct felica *f,
|
||||||
|
struct const_iobuf *req,
|
||||||
|
struct iobuf *res)
|
||||||
|
{
|
||||||
|
uint16_t system_code;
|
||||||
|
uint8_t request_code;
|
||||||
|
uint8_t time_slot;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
/* Request: */
|
||||||
|
|
||||||
|
hr = iobuf_read_be16(req, &system_code);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = iobuf_read_8(req, &request_code);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = iobuf_read_8(req, &time_slot);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (system_code != 0xFFFF && system_code != f->system_code) {
|
||||||
|
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO handle other params correctly...
|
||||||
|
|
||||||
|
/* Response: */
|
||||||
|
|
||||||
|
hr = iobuf_write_be64(res, f->IDm);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = iobuf_write_be64(res, f->PMm);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request_code == 0x01) {
|
||||||
|
hr = iobuf_write_be16(res, f->system_code);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT felica_cmd_get_system_code(
|
||||||
|
struct felica *f,
|
||||||
|
struct const_iobuf *req,
|
||||||
|
struct iobuf *res)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
hr = iobuf_write_8(res, 1); /* Number of system codes */
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = iobuf_write_be16(res, f->system_code);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT felica_cmd_nda_a4(
|
||||||
|
struct felica *f,
|
||||||
|
struct const_iobuf *req,
|
||||||
|
struct iobuf *res)
|
||||||
|
{
|
||||||
|
/* The specification for this command is probably only available under NDA.
|
||||||
|
Returning what the driver seems to want. */
|
||||||
|
|
||||||
|
return iobuf_write_8(res, 0);
|
||||||
|
}
|
27
iccard/felica.h
Normal file
27
iccard/felica.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "hook/iobuf.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FELICA_CMD_POLL = 0x00,
|
||||||
|
FELICA_CMD_GET_SYSTEM_CODE = 0x0c,
|
||||||
|
FELICA_CMD_NDA_A4 = 0xa4,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct felica {
|
||||||
|
uint64_t IDm;
|
||||||
|
uint64_t PMm;
|
||||||
|
uint16_t system_code;
|
||||||
|
};
|
||||||
|
|
||||||
|
HRESULT felica_transact(
|
||||||
|
struct felica *f,
|
||||||
|
struct const_iobuf *req,
|
||||||
|
struct iobuf *res);
|
||||||
|
|
||||||
|
uint64_t felica_get_generic_PMm(void);
|
@ -7,5 +7,7 @@ iccard_lib = static_library(
|
|||||||
capnhook.get_variable('hook_dep'),
|
capnhook.get_variable('hook_dep'),
|
||||||
],
|
],
|
||||||
sources : [
|
sources : [
|
||||||
|
'felica.c',
|
||||||
|
'felica.h',
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user