diff --git a/src/main/acio/acio.h b/src/main/acio/acio.h index 0247ebb..34579f0 100644 --- a/src/main/acio/acio.h +++ b/src/main/acio/acio.h @@ -5,6 +5,7 @@ #include #include +#include "acio/hdxs.h" #include "acio/icca.h" #include "acio/kfca.h" @@ -71,6 +72,8 @@ struct ac_io_message { struct ac_io_kfca_poll_in kfca_poll_in; struct ac_io_kfca_poll_out kfca_poll_out; + + struct ac_io_hdxs_output hdxs_output; }; } cmd; diff --git a/src/main/acio/hdxs.h b/src/main/acio/hdxs.h new file mode 100644 index 0000000..35e3da4 --- /dev/null +++ b/src/main/acio/hdxs.h @@ -0,0 +1,48 @@ +#ifndef ACIO_HDXS_H +#define ACIO_HDXS_H + +#include + +enum ac_io_hdxs_cmd { + AC_IO_HDXS_CMD_SET_OUTPUTS = 0x0112, +}; + +#pragma pack(push, 1) +struct ac_io_hdxs_light { + uint8_t analog : 7; // rgb component + uint8_t bit : 1; // buttons +}; + +struct ac_io_hdxs_output { + uint8_t empty; + struct ac_io_hdxs_light lights[12]; +}; + +enum ac_io_hdxs_front_panel_lights { + AC_IO_HDXS_OUT_P1_START = 0, + AC_IO_HDXS_OUT_P1_UP_DOWN = 1, + AC_IO_HDXS_OUT_P1_LEFT_RIGHT = 2, + AC_IO_HDXS_OUT_P2_START = 3, + AC_IO_HDXS_OUT_P2_UP_DOWN = 4, + AC_IO_HDXS_OUT_P2_LEFT_RIGHT = 5, +}; + +enum ac_io_hdxs_grb_layout { + AC_IO_HDXS_GREEN = 0, + AC_IO_HDXS_RED = 1, + AC_IO_HDXS_BLUE = 2, +}; + +enum ac_io_hdxs_speaker_lights { + AC_IO_HDXS_OUT_P1_SPEAKER_F = 0, + AC_IO_HDXS_OUT_P2_SPEAKER_F = 1, + AC_IO_HDXS_OUT_P1_SPEAKER_W = 2, + AC_IO_HDXS_OUT_P2_SPEAKER_W = 3, +}; + +_Static_assert( + sizeof(struct ac_io_hdxs_output) == 13, + "ac_io_hdxs_output is the wrong size"); +#pragma pack(pop) + +#endif diff --git a/src/main/acioemu/hdxs.c b/src/main/acioemu/hdxs.c index 0e68aa0..725b2f0 100644 --- a/src/main/acioemu/hdxs.c +++ b/src/main/acioemu/hdxs.c @@ -1,5 +1,6 @@ #define LOG_MODULE "acioemu-hdxs" +#include "acio/hdxs.h" #include "acio/acio.h" #include "acioemu/emu.h" @@ -18,12 +19,20 @@ static void ac_io_emu_hdxs_send_status( const struct ac_io_message *req, uint8_t status); -void ac_io_emu_hdxs_init(struct ac_io_emu_hdxs *hdxs, struct ac_io_emu *emu) +void ac_io_emu_hdxs_init( + struct ac_io_emu_hdxs *hdxs, + struct ac_io_emu *emu, + acio_hdxs_dispatcher lights_dispatcher) { log_assert(hdxs != NULL); log_assert(emu != NULL); + if (lights_dispatcher == NULL) { + log_warning("passed in NULL lights_dispatcher"); + } + hdxs->emu = emu; + hdxs->lights_dispatcher = lights_dispatcher; } void ac_io_emu_hdxs_dispatch_request( @@ -51,9 +60,19 @@ void ac_io_emu_hdxs_dispatch_request( case AC_IO_CMD_CLEAR: log_misc("AC_IO_CMD_CLEAR(%d)", req->addr); + ac_io_emu_hdxs_send_status(hdxs, req, 0x00); + + break; + + case AC_IO_HDXS_CMD_SET_OUTPUTS: + if (hdxs->lights_dispatcher != NULL) { + hdxs->lights_dispatcher(hdxs, req); + } + ac_io_emu_hdxs_send_status(hdxs, req, 0x00); + + break; case 0x110: - case 0x112: case 0x128: ac_io_emu_hdxs_send_status(hdxs, req, 0x00); diff --git a/src/main/acioemu/hdxs.h b/src/main/acioemu/hdxs.h index 1016258..111ca44 100644 --- a/src/main/acioemu/hdxs.h +++ b/src/main/acioemu/hdxs.h @@ -5,12 +5,21 @@ #include "acioemu/emu.h" +struct ac_io_emu_hdxs; +struct ac_io_message; + +typedef void (*acio_hdxs_dispatcher)( + struct ac_io_emu_hdxs *emu, const struct ac_io_message *req); + struct ac_io_emu_hdxs { struct ac_io_emu *emu; - // TODO ops vtbl + acio_hdxs_dispatcher lights_dispatcher; }; -void ac_io_emu_hdxs_init(struct ac_io_emu_hdxs *hdxs, struct ac_io_emu *emu); +void ac_io_emu_hdxs_init( + struct ac_io_emu_hdxs *hdxs, + struct ac_io_emu *emu, + acio_hdxs_dispatcher lights_dispatcher); void ac_io_emu_hdxs_dispatch_request( struct ac_io_emu_hdxs *hdxs, const struct ac_io_message *req); diff --git a/src/main/ddrhook/_com4.c b/src/main/ddrhook/_com4.c index 2e37c36..049c8ec 100644 --- a/src/main/ddrhook/_com4.c +++ b/src/main/ddrhook/_com4.c @@ -11,10 +11,14 @@ #include #include +#include "acio/hdxs.h" + #include "acioemu/addr.h" #include "acioemu/hdxs.h" #include "acioemu/icca.h" +#include "bemanitools/ddrio.h" + #include "ddrhook/_com4.h" #include "hook/iohook.h" @@ -29,6 +33,54 @@ static struct ac_io_emu com4_ac_io_emu; static struct ac_io_emu_hdxs com4_hdxs; static struct ac_io_emu_icca com4_icca[2]; +static uint32_t check_panel_light( + const struct ac_io_hdxs_output *output, + uint8_t panel_idx, + uint8_t out_idx) +{ + if (output->lights[panel_idx].bit) { + return 1 << out_idx; + } else { + return 0; + } +} + +static uint8_t upscale_light(uint8_t in_7bit) { + if (in_7bit < 0x10) { + return in_7bit * 2; + } else { + // so we can actually reach 0xFF + return (in_7bit * 2) + 1; + } +} + +static void lights_dispatcher( + struct ac_io_emu_hdxs *emu, const struct ac_io_message *req) +{ + const struct ac_io_hdxs_output *output = &req->cmd.hdxs_output; + + uint32_t lights = 0; + lights |= check_panel_light(output, AC_IO_HDXS_OUT_P1_START, LIGHT_HD_P1_START); + lights |= check_panel_light(output, AC_IO_HDXS_OUT_P1_UP_DOWN, LIGHT_HD_P1_UP_DOWN); + lights |= check_panel_light(output, AC_IO_HDXS_OUT_P1_LEFT_RIGHT, LIGHT_HD_P1_LEFT_RIGHT); + lights |= check_panel_light(output, AC_IO_HDXS_OUT_P2_START, LIGHT_HD_P2_START); + lights |= check_panel_light(output, AC_IO_HDXS_OUT_P2_UP_DOWN, LIGHT_HD_P2_UP_DOWN); + lights |= check_panel_light(output, AC_IO_HDXS_OUT_P2_LEFT_RIGHT, LIGHT_HD_P2_LEFT_RIGHT); + + ddr_io_set_lights_hdxs_panel(lights); + + for (uint8_t i = 0; i < 4; ++i) { + size_t light_idx = i * 3; + + // these are 7 bit, upscale them to 8 bit + uint8_t r = upscale_light(output->lights[light_idx + AC_IO_HDXS_RED].analog); + uint8_t g = upscale_light(output->lights[light_idx + AC_IO_HDXS_GREEN].analog); + uint8_t b = upscale_light(output->lights[light_idx + AC_IO_HDXS_BLUE].analog); + + ddr_io_set_lights_hdxs_rgb(i, r, g, b); + } +} + void com4_init(void) { uint8_t i; @@ -38,7 +90,7 @@ void com4_init(void) p3io_uart_set_path(0, L"COM4"); ac_io_emu_init(&com4_ac_io_emu, L"COM4"); - ac_io_emu_hdxs_init(&com4_hdxs, &com4_ac_io_emu); + ac_io_emu_hdxs_init(&com4_hdxs, &com4_ac_io_emu, lights_dispatcher); for (i = 0; i < lengthof(com4_icca); i++) { ac_io_emu_icca_init(&com4_icca[i], &com4_ac_io_emu, i);