Bemanitools v5.26 release
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
dlls += eamio
|
||||
libs_eamio := geninput util
|
||||
src_eamio := \
|
||||
eam-api.c \
|
||||
eam-impl.c \
|
||||
eam-s11n.c \
|
||||
@@ -0,0 +1,258 @@
|
||||
#include <windows.h>
|
||||
#include <dbt.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bemanitools/eamio.h"
|
||||
#include "bemanitools/input.h"
|
||||
|
||||
#include "eamio/eam-config.h"
|
||||
#include "eamio/eam-impl.h"
|
||||
#include "eamio/eam-s11n.h"
|
||||
|
||||
#include "util/fs.h"
|
||||
#include "util/log.h"
|
||||
#include "util/msg-thread.h"
|
||||
#include "util/thread.h"
|
||||
|
||||
static void eam_handle_hotplug_msg(WPARAM wparam,
|
||||
const DEV_BROADCAST_HDR *hdr);
|
||||
static FILE *eam_io_config_open(const char *mode);
|
||||
static void eam_io_config_load(void);
|
||||
static void eam_io_config_save(void);
|
||||
static bool eam_io_get_autogen(void);
|
||||
static void eam_io_set_autogen(bool autogen);
|
||||
static bool eam_io_get_alt_10k(void);
|
||||
static void eam_io_set_alt_10k(bool alt_10k);
|
||||
static struct hid_stub *eam_io_get_keypad_device(uint8_t unit_no);
|
||||
static void eam_io_set_keypad_device(uint8_t unit_no, struct hid_stub *hid);
|
||||
static const char *eam_io_get_card_path(uint8_t unit_no);
|
||||
static void eam_io_set_card_path(uint8_t unit_no, const char *path);
|
||||
|
||||
static HANDLE eam_hinst;
|
||||
static struct eam *eam_inst;
|
||||
|
||||
static const struct eam_io_config_api eam_io_config_api = {
|
||||
.config_save = eam_io_config_save,
|
||||
.get_autogen = eam_io_get_autogen,
|
||||
.set_autogen = eam_io_set_autogen,
|
||||
.get_alt_10k = eam_io_get_alt_10k,
|
||||
.set_alt_10k = eam_io_set_alt_10k,
|
||||
.get_keypad_device = eam_io_get_keypad_device,
|
||||
.set_keypad_device = eam_io_set_keypad_device,
|
||||
.get_card_path = eam_io_get_card_path,
|
||||
.set_card_path = eam_io_set_card_path,
|
||||
};
|
||||
|
||||
void msg_window_setup(HWND hwnd)
|
||||
{
|
||||
log_info("Drive insertion listener ready, thread id = %d",
|
||||
(int) GetCurrentThreadId());
|
||||
}
|
||||
|
||||
LRESULT WINAPI msg_window_proc(HWND hwnd, UINT msg, WPARAM wparam,
|
||||
LPARAM lparam)
|
||||
{
|
||||
switch (msg) {
|
||||
case WM_DEVICECHANGE:
|
||||
eam_handle_hotplug_msg(wparam, (DEV_BROADCAST_HDR *) lparam);
|
||||
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
}
|
||||
|
||||
static void eam_handle_hotplug_msg(WPARAM wparam, const DEV_BROADCAST_HDR *hdr)
|
||||
{
|
||||
uint32_t drives;
|
||||
unsigned long bit;
|
||||
const DEV_BROADCAST_VOLUME *vol;
|
||||
|
||||
if (wparam != DBT_DEVICEARRIVAL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hdr->dbch_devicetype != DBT_DEVTYP_VOLUME) {
|
||||
return;
|
||||
}
|
||||
|
||||
vol = (const DEV_BROADCAST_VOLUME *) hdr;
|
||||
drives = vol->dbcv_unitmask;
|
||||
|
||||
while (_BitScanForward(&bit, drives)) {
|
||||
drives &= ~(1 << bit);
|
||||
eam_impl_notify_hotplug(eam_inst, (uint8_t) bit);
|
||||
}
|
||||
}
|
||||
|
||||
void msg_window_teardown(HWND hwnd)
|
||||
{
|
||||
log_info("Volume insertion listener shutting down");
|
||||
}
|
||||
|
||||
static FILE *eam_io_config_open(const char *mode)
|
||||
{
|
||||
return fopen_appdata("DJHACKERS", "eam_v4_22.bin", mode);
|
||||
}
|
||||
|
||||
void eam_io_set_loggers(log_formatter_t misc, log_formatter_t info,
|
||||
log_formatter_t warning, log_formatter_t fatal)
|
||||
{
|
||||
log_to_external(misc, info, warning, fatal);
|
||||
}
|
||||
|
||||
bool eam_io_init(thread_create_t create, thread_join_t join,
|
||||
thread_destroy_t destroy)
|
||||
{
|
||||
input_init(create, join, destroy);
|
||||
thread_api_init(create, join, destroy);
|
||||
eam_io_config_load();
|
||||
msg_thread_init(eam_hinst);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void eam_io_config_load(void)
|
||||
{
|
||||
struct eam *eam;
|
||||
FILE *f;
|
||||
|
||||
f = eam_io_config_open("rb");
|
||||
|
||||
if (f == NULL) {
|
||||
log_warning("Failed to open eam config, using defaults");
|
||||
|
||||
goto open_fail;
|
||||
}
|
||||
|
||||
eam = eam_impl_config_load(f);
|
||||
|
||||
if (eam == NULL) {
|
||||
log_warning("eam config is corrupted, using defaults");
|
||||
|
||||
goto read_fail;
|
||||
}
|
||||
|
||||
eam_inst = eam;
|
||||
|
||||
fclose(f);
|
||||
|
||||
return;
|
||||
|
||||
read_fail:
|
||||
fclose(f);
|
||||
|
||||
open_fail:
|
||||
eam_inst = eam_impl_create();
|
||||
}
|
||||
|
||||
void eam_io_fini(void)
|
||||
{
|
||||
msg_thread_fini();
|
||||
eam_impl_destroy(eam_inst);
|
||||
input_fini();
|
||||
}
|
||||
|
||||
const struct eam_io_config_api *eam_io_get_config_api(void)
|
||||
{
|
||||
return &eam_io_config_api;
|
||||
}
|
||||
|
||||
static void eam_io_config_save(void)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = eam_io_config_open("wb");
|
||||
|
||||
if (f == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
eam_impl_config_save(eam_inst, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static bool eam_io_get_autogen(void)
|
||||
{
|
||||
return eam_impl_get_autogen(eam_inst);
|
||||
}
|
||||
|
||||
static void eam_io_set_autogen(bool autogen)
|
||||
{
|
||||
eam_impl_set_autogen(eam_inst, autogen);
|
||||
}
|
||||
|
||||
static bool eam_io_get_alt_10k(void)
|
||||
{
|
||||
return eam_impl_get_alt_10k(eam_inst);
|
||||
}
|
||||
|
||||
static void eam_io_set_alt_10k(bool alt_10k)
|
||||
{
|
||||
eam_impl_set_alt_10k(eam_inst, alt_10k);
|
||||
}
|
||||
|
||||
static struct hid_stub *eam_io_get_keypad_device(uint8_t unit_no)
|
||||
{
|
||||
return eam_impl_get_keypad_device(eam_inst, unit_no);
|
||||
}
|
||||
|
||||
static void eam_io_set_keypad_device(uint8_t unit_no, struct hid_stub *hid)
|
||||
{
|
||||
eam_impl_set_keypad_device(eam_inst, unit_no, hid);
|
||||
}
|
||||
|
||||
static const char *eam_io_get_card_path(uint8_t unit_no)
|
||||
{
|
||||
return eam_impl_get_card_path(eam_inst, unit_no);
|
||||
}
|
||||
|
||||
static void eam_io_set_card_path(uint8_t unit_no, const char *path)
|
||||
{
|
||||
eam_impl_set_card_path(eam_inst, unit_no, path);
|
||||
}
|
||||
|
||||
uint16_t eam_io_get_keypad_state(uint8_t unit_no)
|
||||
{
|
||||
return eam_impl_get_keypad_state(eam_inst, unit_no);
|
||||
}
|
||||
|
||||
uint8_t eam_io_get_sensor_state(uint8_t unit_no)
|
||||
{
|
||||
if (eam_impl_get_sensor_state(eam_inst, unit_no)) {
|
||||
return (1 << EAM_IO_SENSOR_FRONT) | (1 << EAM_IO_SENSOR_BACK);
|
||||
} else {
|
||||
return 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t eam_io_read_card(uint8_t unit_no, uint8_t *card_id, uint8_t nbytes)
|
||||
{
|
||||
return eam_impl_read_card(eam_inst, unit_no, card_id, nbytes);
|
||||
}
|
||||
|
||||
bool eam_io_card_slot_cmd(uint8_t unit_no, uint8_t cmd)
|
||||
{
|
||||
// ignored
|
||||
return true;
|
||||
}
|
||||
|
||||
bool eam_io_poll(uint8_t unit_no)
|
||||
{
|
||||
// ignored
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *ctx)
|
||||
{
|
||||
if (reason == DLL_PROCESS_ATTACH) {
|
||||
eam_hinst = hinst;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef EAMIO_CONFIG_H
|
||||
#define EAMIO_CONFIG_H
|
||||
|
||||
#include "bemanitools/eamio.h"
|
||||
|
||||
struct eam_io_config_api {
|
||||
void (*config_save)(void);
|
||||
bool (*get_autogen)(void);
|
||||
void (*set_autogen)(bool autogen);
|
||||
bool (*get_alt_10k)(void);
|
||||
void (*set_alt_10k)(bool alt_10k);
|
||||
struct hid_stub *(*get_keypad_device)(uint8_t unit_no);
|
||||
void (*set_keypad_device)(uint8_t unit_no, struct hid_stub *hid);
|
||||
const char *(*get_card_path)(uint8_t unit_no);
|
||||
void (*set_card_path)(uint8_t unit_no, const char *path);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,504 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bemanitools/eamio.h"
|
||||
|
||||
#include "eamio/eam-impl.h"
|
||||
|
||||
#include "geninput/hid-mgr.h"
|
||||
|
||||
#include "util/defs.h"
|
||||
#include "util/fs.h"
|
||||
#include "util/hex.h"
|
||||
#include "util/log.h"
|
||||
#include "util/mem.h"
|
||||
#include "util/str.h"
|
||||
|
||||
#define EAM_SENSOR_COOLDOWN 1000
|
||||
|
||||
struct eam_unit {
|
||||
char *card_path;
|
||||
struct hid_stub *hid;
|
||||
size_t keypad_ctls[EAM_IO_KEYPAD_COUNT];
|
||||
size_t sensor_ctl;
|
||||
bool bound_ctls;
|
||||
uint8_t drive_no;
|
||||
uint32_t sensor_time;
|
||||
bool sensor_hot;
|
||||
};
|
||||
|
||||
struct eam {
|
||||
/* This lock protects drive_no and sensor_time, which get read/written
|
||||
respectively by eam_impl_notify_hotplug, which gets called by the Win32
|
||||
message pump thread. */
|
||||
|
||||
CRITICAL_SECTION lock;
|
||||
struct eam_unit units[EAM_UNIT_COUNT];
|
||||
bool autogen;
|
||||
bool alt_10k;
|
||||
bool mux;
|
||||
};
|
||||
|
||||
static const uint32_t eam_keypad_usages[EAM_IO_KEYPAD_COUNT + 1] = {
|
||||
/* [EAM_KEYPAD_0] = */ 0x00070062,
|
||||
/* [EAM_KEYPAD_1] = */ 0x00070059,
|
||||
/* [EAM_KEYPAD_4] = */ 0x0007005C,
|
||||
/* [EAM_KEYPAD_7] = */ 0x0007005F,
|
||||
/* [EAM_KEYPAD_00] = */ 0x00070058, /* Keypad ENTER */
|
||||
/* [EAM_KEYPAD_2] = */ 0x0007005A,
|
||||
/* [EAM_KEYPAD_5] = */ 0x0007005D,
|
||||
/* [EAM_KEYPAD_8] = */ 0x00070060,
|
||||
/* [EAM_KEYPAD_DECIMAL] = */ 0x00070063,
|
||||
/* [EAM_KEYPAD_3] = */ 0x0007005B,
|
||||
/* [EAM_KEYPAD_6] = */ 0x0007005E,
|
||||
/* [EAM_KEYPAD_9] = */ 0x00070061,
|
||||
/* Sensor = */ 0x00070057
|
||||
};
|
||||
|
||||
static const uint32_t eam_keypad_usages_alt[EAM_IO_KEYPAD_COUNT + 1] = {
|
||||
/* [EAM_KEYPAD_0] = */ 0x00070027,
|
||||
/* [EAM_KEYPAD_1] = */ 0x0007001E,
|
||||
/* [EAM_KEYPAD_4] = */ 0x00070021,
|
||||
/* [EAM_KEYPAD_7] = */ 0x00070024,
|
||||
/* [EAM_KEYPAD_00] = */ 0x0007002D, /* - and _ */
|
||||
/* [EAM_KEYPAD_2] = */ 0x0007001F,
|
||||
/* [EAM_KEYPAD_5] = */ 0x00070022,
|
||||
/* [EAM_KEYPAD_8] = */ 0x00070025,
|
||||
/* [EAM_KEYPAD_DECIMAL] = */ 0x0007002E, /* + and = */
|
||||
/* [EAM_KEYPAD_3] = */ 0x00070020,
|
||||
/* [EAM_KEYPAD_6] = */ 0x00070023,
|
||||
/* [EAM_KEYPAD_9] = */ 0x00070026,
|
||||
/* Sensor = */ 0x0007002A /* Backspace */
|
||||
};
|
||||
|
||||
static uint8_t eam_impl_get_active_unit(void);
|
||||
static void eam_impl_bind_keypad(struct eam *eam, uint8_t unit_no);
|
||||
static bool eam_impl_autogen(struct eam_unit *unit, uint8_t *card_id);
|
||||
|
||||
struct eam *eam_impl_create(void)
|
||||
{
|
||||
struct eam *eam;
|
||||
struct eam_unit *unit;
|
||||
size_t btn_no;
|
||||
uint8_t unit_no;
|
||||
|
||||
eam = xmalloc(sizeof(*eam));
|
||||
|
||||
InitializeCriticalSection(&eam->lock);
|
||||
|
||||
for (unit_no = 0 ; unit_no < lengthof(eam->units) ; unit_no++) {
|
||||
unit = &eam->units[unit_no];
|
||||
|
||||
unit->card_path = NULL;
|
||||
unit->hid = NULL;
|
||||
|
||||
for (btn_no = 0 ; btn_no < lengthof(unit->keypad_ctls) ; btn_no++) {
|
||||
unit->keypad_ctls[btn_no] = (size_t) -1;
|
||||
}
|
||||
|
||||
unit->sensor_ctl = (size_t) -1;
|
||||
unit->bound_ctls = false;
|
||||
unit->drive_no = (uint8_t) -1;
|
||||
unit->sensor_time = 0;
|
||||
}
|
||||
|
||||
eam->autogen = false;
|
||||
eam->alt_10k = false;
|
||||
eam->mux = false;
|
||||
|
||||
return eam;
|
||||
}
|
||||
|
||||
static uint8_t eam_impl_get_active_unit(void)
|
||||
{
|
||||
return GetKeyState(VK_NUMLOCK) & 0x0001;
|
||||
}
|
||||
|
||||
bool eam_impl_get_autogen(struct eam *eam)
|
||||
{
|
||||
return eam->autogen;
|
||||
}
|
||||
|
||||
void eam_impl_set_autogen(struct eam *eam, bool autogen)
|
||||
{
|
||||
eam->autogen = autogen != false;
|
||||
}
|
||||
|
||||
bool eam_impl_get_alt_10k(struct eam *eam)
|
||||
{
|
||||
return eam->alt_10k;
|
||||
}
|
||||
|
||||
void eam_impl_set_alt_10k(struct eam *eam, bool alt_10k)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < lengthof(eam->units) ; i++) {
|
||||
eam->units[i].bound_ctls = false;
|
||||
}
|
||||
|
||||
eam->alt_10k = alt_10k != false;
|
||||
}
|
||||
|
||||
struct hid_stub *eam_impl_get_keypad_device(struct eam *eam, uint8_t unit_no)
|
||||
{
|
||||
log_assert(unit_no < lengthof(eam->units));
|
||||
|
||||
return eam->units[unit_no].hid;
|
||||
}
|
||||
|
||||
void eam_impl_set_keypad_device(struct eam *eam, uint8_t unit_no,
|
||||
struct hid_stub *hid)
|
||||
{
|
||||
log_assert(unit_no < lengthof(eam->units));
|
||||
|
||||
eam->units[unit_no].hid = hid;
|
||||
eam->units[unit_no].bound_ctls = false;
|
||||
|
||||
eam->mux = hid != NULL && eam->units[0].hid == eam->units[1].hid;
|
||||
}
|
||||
|
||||
const char *eam_impl_get_card_path(struct eam *eam, uint8_t unit_no)
|
||||
{
|
||||
log_assert(unit_no < lengthof(eam->units));
|
||||
|
||||
return eam->units[unit_no].card_path;
|
||||
}
|
||||
|
||||
void eam_impl_set_card_path(struct eam *eam, uint8_t unit_no,
|
||||
const char *path)
|
||||
{
|
||||
log_assert(unit_no < lengthof(eam->units));
|
||||
|
||||
EnterCriticalSection(&eam->lock);
|
||||
|
||||
free(eam->units[unit_no].card_path);
|
||||
|
||||
if (path != NULL) {
|
||||
eam->units[unit_no].card_path = str_dup(path);
|
||||
|
||||
if (isalpha(path[0]) && path[1] == ':') {
|
||||
eam->units[unit_no].drive_no = toupper(path[0]) - 'A';
|
||||
} else {
|
||||
eam->units[unit_no].drive_no = (uint8_t) -1;
|
||||
}
|
||||
} else {
|
||||
eam->units[unit_no].card_path = NULL;
|
||||
eam->units[unit_no].drive_no = (uint8_t) -1;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&eam->lock);
|
||||
}
|
||||
|
||||
uint16_t eam_impl_get_keypad_state(struct eam *eam, uint8_t unit_no)
|
||||
{
|
||||
struct eam_unit *unit;
|
||||
uint16_t result;
|
||||
int32_t value;
|
||||
size_t i;
|
||||
|
||||
log_assert(unit_no < lengthof(eam->units));
|
||||
|
||||
if (eam->mux && eam_impl_get_active_unit() != unit_no) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
eam_impl_bind_keypad(eam, unit_no);
|
||||
|
||||
unit = &eam->units[unit_no];
|
||||
result = 0;
|
||||
|
||||
if (unit->bound_ctls) {
|
||||
for (i = 0 ; i < lengthof(unit->keypad_ctls) ; i++) {
|
||||
if (unit->keypad_ctls[i] == (size_t) -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hid_stub_get_value(unit->hid, unit->keypad_ctls[i], &value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value) {
|
||||
result |= 1 << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void eam_impl_bind_keypad(struct eam *eam, uint8_t unit_no)
|
||||
{
|
||||
const uint32_t *usages;
|
||||
struct hid_control *controls;
|
||||
struct eam_unit *unit;
|
||||
size_t ncontrols;
|
||||
size_t control_no;
|
||||
size_t btn_no;
|
||||
|
||||
unit = &eam->units[unit_no];
|
||||
|
||||
if (unit->bound_ctls
|
||||
|| unit->hid == NULL
|
||||
|| !hid_stub_is_attached(unit->hid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (eam->alt_10k) {
|
||||
usages = eam_keypad_usages_alt;
|
||||
} else {
|
||||
usages = eam_keypad_usages;
|
||||
}
|
||||
|
||||
/* Set flag first: don't try again if this fails for whatever reason. */
|
||||
|
||||
unit->bound_ctls = true;
|
||||
|
||||
hid_mgr_lock();
|
||||
|
||||
if (!hid_stub_get_controls(unit->hid, NULL, &ncontrols)) {
|
||||
goto size_fail;
|
||||
}
|
||||
|
||||
controls = xmalloc(ncontrols * sizeof(*controls));
|
||||
|
||||
if (!hid_stub_get_controls(unit->hid, controls, &ncontrols)) {
|
||||
goto content_fail;
|
||||
}
|
||||
|
||||
for (control_no = 0 ; control_no < ncontrols ; control_no++) {
|
||||
for (btn_no = 0 ; btn_no < EAM_IO_KEYPAD_COUNT ; btn_no++) {
|
||||
if (controls[control_no].usage == usages[btn_no]) {
|
||||
unit->keypad_ctls[btn_no] = control_no;
|
||||
}
|
||||
}
|
||||
|
||||
if (controls[control_no].usage == usages[EAM_IO_KEYPAD_COUNT]) {
|
||||
unit->sensor_ctl = control_no;
|
||||
}
|
||||
}
|
||||
|
||||
free(controls);
|
||||
|
||||
hid_mgr_unlock();
|
||||
|
||||
return;
|
||||
|
||||
content_fail:
|
||||
free(controls);
|
||||
|
||||
size_fail:
|
||||
hid_mgr_unlock();
|
||||
}
|
||||
|
||||
bool eam_impl_get_sensor_state(struct eam *eam, uint8_t unit_no)
|
||||
{
|
||||
struct eam_unit *unit;
|
||||
uint32_t now;
|
||||
int32_t value;
|
||||
bool result;
|
||||
|
||||
log_assert(unit_no < lengthof(eam->units));
|
||||
|
||||
unit = &eam->units[unit_no];
|
||||
result = false;
|
||||
|
||||
eam_impl_bind_keypad(eam, unit_no);
|
||||
|
||||
if (!unit->bound_ctls) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (unit->sensor_ctl == (size_t) -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hid_stub_get_value(unit->hid, unit->sensor_ctl, &value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
now = GetTickCount();
|
||||
|
||||
EnterCriticalSection(&eam->lock);
|
||||
|
||||
/* Bump cooldown as long as sensor button is held
|
||||
(cooldown timer might also be set by a USB hotplug event) */
|
||||
|
||||
if (value != 0 && (!eam->mux || eam_impl_get_active_unit() == unit_no)) {
|
||||
unit->sensor_time = now + EAM_SENSOR_COOLDOWN;
|
||||
unit->sensor_hot = true;
|
||||
}
|
||||
|
||||
if (unit->sensor_hot) {
|
||||
if ((int32_t) (unit->sensor_time - now) > 0) {
|
||||
result = true;
|
||||
} else {
|
||||
unit->sensor_time = 0;
|
||||
unit->sensor_hot = false;
|
||||
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&eam->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t eam_impl_read_card(struct eam *eam, uint8_t unit_no, uint8_t *card_id,
|
||||
uint8_t nbytes)
|
||||
{
|
||||
char line[128];
|
||||
struct eam_unit *unit;
|
||||
size_t len;
|
||||
FILE *f;
|
||||
|
||||
log_assert(unit_no < lengthof(eam->units));
|
||||
log_assert(card_id != NULL);
|
||||
log_assert(nbytes == EAM_CARD_NBYTES);
|
||||
|
||||
unit = &eam->units[unit_no];
|
||||
|
||||
if (unit->card_path == NULL) {
|
||||
goto path_fail;
|
||||
}
|
||||
|
||||
f = fopen(unit->card_path, "r");
|
||||
|
||||
if (f == NULL) {
|
||||
if (eam->autogen) {
|
||||
if (!eam_impl_autogen(unit, card_id)) {
|
||||
log_warning("Unit %d: Failed to generate card ID into %s",
|
||||
unit_no, unit->card_path);
|
||||
|
||||
goto fopen_fail;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
log_warning("Unit %d: Card file at %s not present",
|
||||
unit_no, unit->card_path);
|
||||
|
||||
goto fopen_fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (fgets(line, sizeof(line), f) == NULL) {
|
||||
log_warning("%s: fgets() failed", unit->card_path);
|
||||
|
||||
goto fgets_fail;
|
||||
}
|
||||
|
||||
str_trim(line);
|
||||
len = strlen(line);
|
||||
|
||||
if (len != 2 * EAM_CARD_NBYTES) {
|
||||
log_warning("%s: Expected %u chars (got %u)",
|
||||
unit->card_path, 2 * EAM_CARD_NBYTES, (unsigned int) len);
|
||||
|
||||
goto len_fail;
|
||||
}
|
||||
|
||||
if (!hex_decode(card_id, nbytes, line, len)) {
|
||||
log_warning("%s: Invalid hex [%s]", unit->card_path, card_id);
|
||||
|
||||
goto decode_fail;
|
||||
}
|
||||
|
||||
log_misc("Unit %d: Loaded card ID [%s] from file %s",
|
||||
unit_no, line, unit->card_path);
|
||||
|
||||
fclose(f);
|
||||
|
||||
if (card_id[0] == 0xe0 && card_id[1] == 0x04) {
|
||||
return EAM_IO_CARD_ISO15696;
|
||||
} else {
|
||||
return EAM_IO_CARD_FELICA;
|
||||
}
|
||||
|
||||
decode_fail:
|
||||
len_fail:
|
||||
fgets_fail:
|
||||
fclose(f);
|
||||
|
||||
fopen_fail:
|
||||
path_fail:
|
||||
return EAM_IO_CARD_NONE;
|
||||
}
|
||||
|
||||
static bool eam_impl_autogen(struct eam_unit *unit, uint8_t *card_id)
|
||||
{
|
||||
char hex[2 * EAM_CARD_NBYTES + 1];
|
||||
FILE *f;
|
||||
size_t i;
|
||||
|
||||
f = fopen(unit->card_path, "w");
|
||||
|
||||
if (f == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
srand(GetTickCount());
|
||||
|
||||
card_id[0] = 0xE0;
|
||||
card_id[1] = 0x04;
|
||||
card_id[2] = 0x01;
|
||||
card_id[3] = 0x00;
|
||||
|
||||
for (i = 4 ; i < 8 ; i++) {
|
||||
/* LSBit entropy of typical LFSR RNGs is usually poor */
|
||||
card_id[i] = rand() >> 7;
|
||||
}
|
||||
|
||||
hex_encode_uc(card_id, EAM_CARD_NBYTES, hex, sizeof(hex));
|
||||
fwrite(hex, sizeof(hex) - 1, 1, f);
|
||||
|
||||
fclose(f);
|
||||
|
||||
log_info("Generated random card ID [%s] into file %s",
|
||||
hex, unit->card_path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void eam_impl_notify_hotplug(struct eam *eam, uint8_t drive_no)
|
||||
{
|
||||
struct eam_unit *unit;
|
||||
uint8_t unit_no;
|
||||
|
||||
EnterCriticalSection(&eam->lock);
|
||||
|
||||
for (unit_no = 0 ; unit_no < lengthof(eam->units) ; unit_no++) {
|
||||
if (eam->units[unit_no].drive_no == drive_no) {
|
||||
/* MMSYSTEM timeGetTime() is overkill, we don't exactly need super
|
||||
accurate timestamps here. */
|
||||
|
||||
unit = &eam->units[unit_no];
|
||||
|
||||
unit->sensor_time = GetTickCount() + EAM_SENSOR_COOLDOWN;
|
||||
unit->sensor_hot = true;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&eam->lock);
|
||||
}
|
||||
|
||||
void eam_impl_destroy(struct eam *eam)
|
||||
{
|
||||
int8_t unit_no;
|
||||
|
||||
for (unit_no = lengthof(eam->units) - 1 ; unit_no >= 0 ; unit_no--) {
|
||||
free(eam->units[unit_no].card_path);
|
||||
}
|
||||
|
||||
DeleteCriticalSection(&eam->lock);
|
||||
|
||||
free(eam);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef EAMIO_EAM_IMPL_H
|
||||
#define EAMIO_EAM_IMPL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bemanitools/eamio.h"
|
||||
|
||||
#include "geninput/hid-mgr.h"
|
||||
|
||||
#define EAM_CARD_NBYTES 8
|
||||
#define EAM_UNIT_COUNT 2
|
||||
|
||||
struct eam;
|
||||
|
||||
struct eam *eam_impl_create(void);
|
||||
bool eam_impl_get_autogen(struct eam *eam);
|
||||
void eam_impl_set_autogen(struct eam *eam, bool autogen);
|
||||
bool eam_impl_get_alt_10k(struct eam *eam);
|
||||
void eam_impl_set_alt_10k(struct eam *eam, bool alt_10k);
|
||||
struct hid_stub *eam_impl_get_keypad_device(struct eam *eam, uint8_t unit_no);
|
||||
void eam_impl_set_keypad_device(struct eam *eam, uint8_t unit_no,
|
||||
struct hid_stub *hid);
|
||||
const char *eam_impl_get_card_path(struct eam *eam, uint8_t unit_no);
|
||||
void eam_impl_set_card_path(struct eam *eam, uint8_t unit_no,
|
||||
const char *path);
|
||||
uint16_t eam_impl_get_keypad_state(struct eam *eam, uint8_t unit_no);
|
||||
bool eam_impl_get_sensor_state(struct eam *eam, uint8_t unit_no);
|
||||
uint8_t eam_impl_read_card(struct eam *eam, uint8_t unit_no, uint8_t *card_id,
|
||||
uint8_t nbytes);
|
||||
void eam_impl_notify_hotplug(struct eam *eam, uint8_t drive_no);
|
||||
void eam_impl_destroy(struct eam *eam);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,122 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "eamio/eam-impl.h"
|
||||
#include "eamio/eam-s11n.h"
|
||||
|
||||
#include "util/fs.h"
|
||||
|
||||
struct eam *eam_impl_config_load(FILE *f)
|
||||
{
|
||||
struct eam *eam;
|
||||
struct hid_stub *hid;
|
||||
int8_t nunits;
|
||||
int8_t unit_no;
|
||||
char *card_path;
|
||||
char *dev_node;
|
||||
bool autogen;
|
||||
bool alt_10k;
|
||||
bool has_card_path;
|
||||
bool has_hid;
|
||||
|
||||
eam = eam_impl_create();
|
||||
|
||||
if (!read_u8(f, &autogen)) {
|
||||
goto early_fail;
|
||||
}
|
||||
|
||||
if (!read_u8(f, &alt_10k)) {
|
||||
goto early_fail;
|
||||
}
|
||||
|
||||
eam_impl_set_autogen(eam, autogen);
|
||||
eam_impl_set_alt_10k(eam, alt_10k);
|
||||
|
||||
if (!read_u8(f, &nunits) || nunits != EAM_UNIT_COUNT) {
|
||||
goto early_fail;
|
||||
}
|
||||
|
||||
hid_mgr_lock();
|
||||
|
||||
for (unit_no = 0 ; unit_no < EAM_UNIT_COUNT ; unit_no++) {
|
||||
if (!read_u8(f, &has_card_path)) {
|
||||
goto late_fail;
|
||||
}
|
||||
|
||||
if (!read_u8(f, &has_hid)) {
|
||||
goto late_fail;
|
||||
}
|
||||
|
||||
if (has_card_path) {
|
||||
if (!read_str(f, &card_path)) {
|
||||
goto late_fail;
|
||||
}
|
||||
|
||||
eam_impl_set_card_path(eam, unit_no, card_path);
|
||||
free(card_path);
|
||||
}
|
||||
|
||||
if (has_hid) {
|
||||
if (!read_str(f, &dev_node)) {
|
||||
goto late_fail;
|
||||
}
|
||||
|
||||
hid = hid_mgr_get_named_stub(dev_node);
|
||||
eam_impl_set_keypad_device(eam, unit_no, hid);
|
||||
|
||||
free(dev_node);
|
||||
}
|
||||
}
|
||||
|
||||
hid_mgr_unlock();
|
||||
|
||||
return eam;
|
||||
|
||||
late_fail:
|
||||
hid_mgr_unlock();
|
||||
|
||||
early_fail:
|
||||
eam_impl_destroy(eam);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void eam_impl_config_save(struct eam *eam, FILE *f)
|
||||
{
|
||||
const char *card_path;
|
||||
struct hid_stub *hid;
|
||||
uint8_t nunits;
|
||||
uint8_t unit_no;
|
||||
bool autogen;
|
||||
bool alt_10k;
|
||||
bool has_card_path;
|
||||
bool has_hid;
|
||||
|
||||
autogen = eam_impl_get_autogen(eam);
|
||||
alt_10k = eam_impl_get_alt_10k(eam);
|
||||
nunits = EAM_UNIT_COUNT;
|
||||
|
||||
write_u8(f, &autogen);
|
||||
write_u8(f, &alt_10k);
|
||||
write_u8(f, &nunits);
|
||||
|
||||
for (unit_no = 0 ; unit_no < EAM_UNIT_COUNT ; unit_no++) {
|
||||
card_path = eam_impl_get_card_path(eam, unit_no);
|
||||
hid = eam_impl_get_keypad_device(eam, unit_no);
|
||||
|
||||
has_card_path = card_path != NULL;
|
||||
has_hid = hid != NULL;
|
||||
|
||||
write_u8(f, &has_card_path);
|
||||
write_u8(f, &has_hid);
|
||||
|
||||
if (has_card_path) {
|
||||
write_str(f, card_path);
|
||||
}
|
||||
|
||||
if (has_hid) {
|
||||
write_str(f, hid_stub_get_dev_node(hid));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef GENINPUT_EAM_S11N_H
|
||||
#define GENINPUT_EAM_S11N_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "eamio/eam-impl.h"
|
||||
|
||||
struct eam *eam_impl_config_load(FILE *f);
|
||||
void eam_impl_config_save(struct eam *eam, FILE *f);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
LIBRARY eamio
|
||||
|
||||
EXPORTS
|
||||
eam_io_fini
|
||||
eam_io_init
|
||||
eam_io_get_config_api
|
||||
eam_io_get_keypad_state
|
||||
eam_io_get_sensor_state
|
||||
eam_io_read_card
|
||||
eam_io_card_slot_cmd
|
||||
eam_io_set_loggers
|
||||
eam_io_poll
|
||||
Reference in New Issue
Block a user