Files
TeamTofuShop_taitools/board/j9100628a.c
T

488 lines
12 KiB
C

#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include "board/j9100628a.h"
#include "jvs/jvs-bus.h"
#include "jvs/jvs-cmd.h"
#include "jvs/jvs-util.h"
#include "util/dprintf.h"
#include "util/dump.h"
// JVS card reader
static const uint8_t j9100628a_ident[] = "taito;JVS-Reader;Ver1.00;JPN,Multipurpose";
static uint8_t j9100628a_features[] = {
/* Feature : 0x01 : Players and switches
Param1 : 1 : Number of players
Param2 : 18 : Number of switches per player
Param3 : 0 : N/A */
0x01,
0x01,
0x18,
0x00,
/* Feature : 0x02 : Coin slots
Param1 : 2 : Number of coin slots
Param2 : 0 : N/A
Param3 : 0 : N/A */
0x02,
0x00,
0x00,
0x00,
/* Feature : 0x03 : Analog inputs
Param1 : 8 : Number of ADC channels
Param2 : 10 : Effective bits of resolution per ADC
Param3 : 0 : N/A */
0x03,
0x00,
0x00,
0x00,
/* Feature : 0x04 : Rotary Input
Param1 : 4 : Number of Rotary channels
Param2 : 0 : N/A
Param3 : 0 : N/A */
0x04,
0x00,
0x00,
0x00,
/* Feature : 0x12 : GPIO outputs
Param1 : 3 : Number of ports (8 bits per port)
Param2 : 0 : N/A
Param3 : 0 : N/A
*/
0x12,
0x00,
0x00,
0x00,
/* Feature : 0x13 : Analog outputs
Param1 : 2 : Number of channels
Param2 : 0 : N/A
Param3 : 0 : N/A
*/
0x13,
0x00,
0x00,
0x00,
/* Feature : 0x14 : Character Output
Param1 : 0x50 : Width
Param2 : 0x19 : Height
Param3 : 0 : Type
*/
0x14,
0x50,
0x19,
0x00,
/* Feature : 0x00 : End of capabilities */
0x00,
};
static void j9100628a_transact(
struct jvs_node *node,
const void *bytes,
size_t nbytes,
struct iobuf *resp);
static bool j9100628a_sense(struct jvs_node *node);
static HRESULT j9100628a_cmd(
void *ctx,
struct const_iobuf *req,
struct iobuf *resp);
static HRESULT j9100628a_cmd_reset(struct j9100628a *j9100628a, struct const_iobuf *req_buf);
static HRESULT j9100628a_cmd_assign_addr(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf);
static HRESULT j9100628a_cmd_read_id(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf);
static HRESULT j9100628a_cmd_get_cmd_version(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf);
static HRESULT j9100628a_cmd_get_jvs_version(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf);
static HRESULT j9100628a_cmd_get_comm_version(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf);
static HRESULT j9100628a_cmd_get_features(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf);
static HRESULT j9100628a_cmd_read_misc_switches(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf);
static HRESULT j9100628a_cmd_read_dip_switches(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf);
static HRESULT j9100628a_cmd_write_gpio(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf);
void j9100628a_init(
struct j9100628a *j9100628a,
struct jvs_node *next,
const struct j9100628a_ops *ops,
void *ops_ctx)
{
assert(j9100628a != NULL);
assert(ops != NULL);
j9100628a->jvs.next = next;
j9100628a->jvs.transact = j9100628a_transact;
j9100628a->jvs.sense = j9100628a_sense;
j9100628a->jvs.sense_out = true;
j9100628a->addr = 0xFF;
j9100628a->ops = ops;
j9100628a->ops_ctx = ops_ctx;
}
struct jvs_node *j9100628a_to_jvs_node(struct j9100628a *j9100628a)
{
assert(j9100628a != NULL);
return &j9100628a->jvs;
}
static void j9100628a_transact(
struct jvs_node *node,
const void *bytes,
size_t nbytes,
struct iobuf *resp)
{
struct j9100628a *j9100628a;
assert(node != NULL);
assert(bytes != NULL);
assert(resp != NULL);
j9100628a = CONTAINING_RECORD(node, struct j9100628a, jvs);
jvs_crack_request(bytes, nbytes, resp, j9100628a->addr, j9100628a_cmd, j9100628a);
}
static bool j9100628a_sense(struct jvs_node *node)
{
struct j9100628a *j9100628a;
assert(node != NULL);
j9100628a = CONTAINING_RECORD(node, struct j9100628a, jvs);
return j9100628a->addr == 0xFF;
}
static HRESULT j9100628a_cmd(
void *ctx,
struct const_iobuf *req,
struct iobuf *resp)
{
struct j9100628a *j9100628a;
j9100628a = ctx;
switch (req->bytes[req->pos]) {
case JVS_CMD_RESET:
return j9100628a_cmd_reset(j9100628a, req);
case JVS_CMD_ASSIGN_ADDR:
return j9100628a_cmd_assign_addr(j9100628a, req, resp);
case JVS_CMD_READ_ID:
return j9100628a_cmd_read_id(j9100628a, req, resp);
case JVS_CMD_GET_CMD_VERSION:
return j9100628a_cmd_get_cmd_version(j9100628a, req, resp);
case JVS_CMD_GET_JVS_VERSION:
return j9100628a_cmd_get_jvs_version(j9100628a, req, resp);
case JVS_CMD_GET_COMM_VERSION:
return j9100628a_cmd_get_comm_version(j9100628a, req, resp);
case JVS_CMD_GET_FEATURES:
return j9100628a_cmd_get_features(j9100628a, req, resp);
case JVS_CMD_READ_MISC_SWITCHES:
return j9100628a_cmd_read_misc_switches(j9100628a, req, resp);
case JVS_CMD_TYPEX_READ_DIPSW:
return j9100628a_cmd_read_dip_switches(j9100628a, req, resp);
case JVS_CMD_TYPEX_POLL_AMIC:
// FIXME: seperate func
return j9100628a_cmd_read_dip_switches(j9100628a, req, resp);
case JVS_CMD_WRITE_GPIO:
return j9100628a_cmd_write_gpio(j9100628a, req, resp);
default:
dprintf("J9100628A: Node %02x: Unhandled command byte %02x\n",
j9100628a->addr,
req->bytes[req->pos]);
return E_NOTIMPL;
}
return S_OK;
}
static HRESULT j9100628a_cmd_reset(struct j9100628a *j9100628a, struct const_iobuf *req_buf)
{
struct jvs_req_reset req;
HRESULT hr;
hr = iobuf_read(req_buf, &req, sizeof(req));
if (FAILED(hr)) {
return hr;
}
dprintf("J9100628A: Reset (param %02x)\n", req.unknown);
j9100628a->addr = 0xFF;
j9100628a->jvs.sense_out = false; // ?
if (j9100628a->ops->reset != NULL) {
j9100628a->ops->reset(j9100628a->ops_ctx);
}
/* No ack for this since it really is addressed to everybody */
return S_OK;
}
static HRESULT j9100628a_cmd_assign_addr(
struct j9100628a *j9100628a,
struct const_iobuf *req_buf,
struct iobuf *resp_buf)
{
struct jvs_req_assign_addr req;
bool sense;
HRESULT hr;
hr = iobuf_read(req_buf, &req, sizeof(req));
if (FAILED(hr)) {
return hr;
}
sense = jvs_node_sense(j9100628a->jvs.next);
dprintf("J9100628A: Assign addr %02x sense %i\n", req.addr, sense);
if (sense) {
/* That address is for somebody else */
return S_OK;
}
j9100628a->addr = req.addr;
j9100628a->jvs.sense_out = true;
return iobuf_write_8(resp_buf, 0x01);
}
static HRESULT j9100628a_cmd_read_id(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf)
{
uint8_t req;
HRESULT hr;
hr = iobuf_read_8(req_buf, &req);
if (FAILED(hr)) {
return hr;
}
dprintf("J9100628A: Read ID\n");
/* Write report byte */
hr = iobuf_write_8(resp_buf, 0x01);
if (FAILED(hr)) {
return hr;
}
/* Write the identification string. The NUL terminator at the end of this C
string is also sent, and it naturally terminates the response chunk. */
return iobuf_write(resp_buf, j9100628a_ident, sizeof(j9100628a_ident));
}
static HRESULT j9100628a_cmd_get_cmd_version(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf)
{
uint8_t req;
uint8_t resp[2];
HRESULT hr;
hr = iobuf_read_8(req_buf, &req);
if (FAILED(hr)) {
return hr;
}
dprintf("J9100628A: Get command format version\n");
resp[0] = 0x01; /* Report byte */
resp[1] = 0x13; /* Command format version BCD */
return iobuf_write(resp_buf, resp, sizeof(resp));
}
static HRESULT j9100628a_cmd_get_jvs_version(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf)
{
uint8_t req;
uint8_t resp[2];
HRESULT hr;
hr = iobuf_read_8(req_buf, &req);
if (FAILED(hr)) {
return hr;
}
dprintf("J9100628A: Get JVS format version\n");
resp[0] = 0x01; /* Report byte */
resp[1] = 0x30; /* JVS format version BCD */
return iobuf_write(resp_buf, resp, sizeof(resp));
}
static HRESULT j9100628a_cmd_get_comm_version(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf)
{
uint8_t req;
uint8_t resp[2];
HRESULT hr;
hr = iobuf_read_8(req_buf, &req);
if (FAILED(hr)) {
return hr;
}
dprintf("J9100628A: Get COMM format version\n");
resp[0] = 0x01; /* Report byte */
resp[1] = 0x10; /* COMM format version BCD */
return iobuf_write(resp_buf, resp, sizeof(resp));
}
static HRESULT j9100628a_cmd_get_features(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf)
{
uint8_t req;
uint8_t resp[2];
HRESULT hr;
hr = iobuf_read_8(req_buf, &req);
if (FAILED(hr)) {
return hr;
}
dprintf("J9100628A: Get reader features\n");
hr = iobuf_write_8(resp_buf, 0x01); /* Write report byte */
if (FAILED(hr)) {
return hr;
}
return iobuf_write(resp_buf, j9100628a_features, sizeof(j9100628a_features));
}
static HRESULT j9100628a_cmd_read_misc_switches(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf)
{
uint8_t req;
uint8_t resp[2];
HRESULT hr;
hr = iobuf_read_8(req_buf, &req);
if (FAILED(hr)) {
return hr;
}
hr = iobuf_write_8(resp_buf, 0x01); /* Write report byte */
if (FAILED(hr)) {
return hr;
}
return iobuf_write_8(resp_buf, 0x00); /* Write switch byte */
}
static HRESULT j9100628a_cmd_read_dip_switches(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf)
{
uint8_t req;
uint8_t resp[2];
HRESULT hr;
hr = iobuf_read_8(req_buf, &req);
if (FAILED(hr)) {
return hr;
}
hr = iobuf_write_8(resp_buf, 0x01); /* Write report byte */
if (FAILED(hr)) {
return hr;
}
return iobuf_write_8(resp_buf, 0x00); /* Write switch byte */
}
static HRESULT j9100628a_cmd_write_gpio(
struct j9100628a *j9100628a,
struct const_iobuf *req_buf,
struct iobuf *resp_buf)
{
uint8_t cmd;
uint8_t nbytes;
uint8_t bytes[3];
HRESULT hr;
/* Read request header */
hr = iobuf_read_8(req_buf, &cmd);
if (FAILED(hr)) {
return hr;
}
hr = iobuf_read_8(req_buf, &nbytes);
if (FAILED(hr)) {
return hr;
}
if (nbytes > 3) {
dprintf("J9100628A: Invalid GPIO write size %i\n", nbytes);
hr = iobuf_write_8(resp_buf, 0x02);
if (FAILED(hr)) {
return hr;
}
return E_FAIL;
}
/* Read payload */
memset(bytes, 0, sizeof(bytes));
hr = iobuf_read(req_buf, bytes, nbytes);
if (FAILED(hr)) {
return hr;
}
if (j9100628a->ops->write_led != NULL) {
j9100628a->ops->write_led(
j9100628a->ops_ctx,
bytes[0] | (bytes[1] << 8) | (bytes[2] << 16));
}
/* Write report byte */
return iobuf_write_8(resp_buf, 0x01);
}