#include #include #include #include #include #include #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); }