From 7429c134f83ba7e752ed39ca48ca6834c5749c7f Mon Sep 17 00:00:00 2001 From: gered Date: Mon, 15 Feb 2021 18:48:00 -0500 Subject: [PATCH] cleanup a bit, put keyboard init & reading things into a semi-nicer API still pretty low-level. will be fleshing this out more soon. :-) --- CMakeLists.txt | 2 +- src/gckeybrd.c | 83 ++++++++++++++++++++++++++++++++++++++++++ src/gckeybrd.h | 29 +++++++++++++++ src/main.c | 99 ++++++++------------------------------------------ 4 files changed, 128 insertions(+), 85 deletions(-) create mode 100644 src/gckeybrd.c create mode 100644 src/gckeybrd.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5be3850..9f35982 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ project(${PROJECT_NAME} C ASM) set(CMAKE_VERBOSE_MAKEFILE OFF) set(CMAKE_C_STANDARD 99) -add_executable(${PROJECT_NAME}.elf src/main.c) +add_executable(${PROJECT_NAME}.elf src/main.c src/gckeybrd.c) target_link_directories(${PROJECT_NAME}.elf PRIVATE ${DEVKITPRO}/libogc/lib/wii) target_link_libraries(${PROJECT_NAME}.elf PRIVATE db wiiuse bte ogc m) diff --git a/src/gckeybrd.c b/src/gckeybrd.c new file mode 100644 index 0000000..6532dd1 --- /dev/null +++ b/src/gckeybrd.c @@ -0,0 +1,83 @@ +#include + +#if defined(HW_DOL) +#define SI_REG_BASE 0xCC006400 +#elif defined(HW_RVL) +#define SI_REG_BASE 0xCD006400 +#else +#error Hardware model unknown? Missing a preprocessor definition somewhere... +#endif + +#define SIREG(n) ((vu32*)(SI_REG_BASE + (n))) + +#define SICOUTBUF(n) (SIREG(0x00 + (n)*12)) /* SI Channel n Output Buffer (Joy-channel n Command) (4 bytes) */ +#define SICINBUFH(i) (SIREG(0x04 + (i)*12)) /* SI Channel n Input Buffer High (Joy-channel n Buttons 1) (4 bytes) */ +#define SICINBUFL(i) (SIREG(0x08 + (i)*12)) /* SI Channel n Input Buffer Low (Joy-channel n Buttons 2) (4 bytes) */ +#define SIPOLL (SIREG(0x30)) /* SI Poll Register (4 bytes) */ +#define SICOMCSR (SIREG(0x34)) /* SI Communication Control Status Register (command) (4 bytes) */ +#define SISR (SIREG(0x38)) /* SI Status Register (4 bytes) */ +#define SIIOBUF (SIREG(0x80)) /* SI I/O buffer (access by word) (128 bytes) */ + +#define PAD_ENABLEDMASK(chan) (0x80000000 >> chan) + +static void SI_AwaitPendingCommands(void) { + while(*SICOMCSR & 0x1); +} + +int GCKB_Detect(void) { + SI_AwaitPendingCommands(); + + u32 buf[2]; + for (int i = 0; i < 4; ++i) { + SI_GetResponse(i, buf); + SI_SetCommand(i, 0x00400300); + SI_EnablePolling(PAD_ENABLEDMASK(i)); + } + SI_AwaitPendingCommands(); + + int keyboardChan = -1; + + for (int i = 0; i < 4; ++i) { + u32 type = SI_DecodeType(SI_GetType(i)); + if (type == SI_GC_KEYBOARD) + keyboardChan = i; + } + + return keyboardChan; +} + +int GCKB_Init(int chan) { + if (chan == -1) + return 0; + + u32 buf[2]; + + SI_GetResponse(chan, buf); + SI_SetCommand(chan, 0x00540000); + SI_EnablePolling(PAD_ENABLEDMASK(chan)); + SI_TransferCommands(); + SI_AwaitPendingCommands(); + + return 1; +} + +int GCKB_ReadKeys(int chan, u8 *pressedKeys) { + if (chan == -1) + return 0; + if (!pressedKeys) + return 0; + + u32 buffer[2]; + if (SI_GetResponse(chan, buffer)) { + pressedKeys[0] = buffer[1] >> 24; + pressedKeys[1] = (buffer[1] >> 16) & 0xff; + pressedKeys[2] = (buffer[1] >> 8) & 0xff; + return 1; + } else { + pressedKeys[0] = 0; + pressedKeys[1] = 0; + pressedKeys[2] = 0; + } + + return 0; +} \ No newline at end of file diff --git a/src/gckeybrd.h b/src/gckeybrd.h new file mode 100644 index 0000000..61bc0c6 --- /dev/null +++ b/src/gckeybrd.h @@ -0,0 +1,29 @@ +#ifndef GCKEYBRD_H_INCLUDED +#define GCKEYBRD_H_INCLUDED + +#include + +/** + * Attempts to detect the presence of a GC Keyboard Controller connected to any of the controller ports. + * Returns the SI channel of the found keyboard controller, or -1 if one could not be found. + */ +int GCKB_Detect(void); + +/** + * Initializes the keyboard controller, previously detected on the given SI channel. This must be called before + * key press information can be read. Returns 1 on success, 0 on failure. + */ +int GCKB_Init(int chan); + +/** + * Reads current key press information from the previously initialized keyboard controller, located on the given + * SI channel. Returns 1 if key press data has been returned, or 0 on failure. + * + * The pressedKeys buffer passed in should be large enough to hold 3 bytes. Each byte will correspond to one key + * pressed. The keyboard controller can only recognize 3 simultaneous key presses at a time (and, depending on the + * specific keys, probably only 2 at a time). If too many keys are held down, all of the values returned will be 0x02. + * A value of 0x00 indicates no key press. + */ +int GCKB_ReadKeys(int chan, u8 *pressedKeys); + +#endif diff --git a/src/main.c b/src/main.c index 308ebdb..3ecd224 100644 --- a/src/main.c +++ b/src/main.c @@ -3,72 +3,11 @@ #include #include +#include "gckeybrd.h" + static void *xfb = NULL; static GXRModeObj *rmode = NULL; -#if defined(HW_DOL) -#define SI_REG_BASE 0xCC006400 -#elif defined(HW_RVL) -#define SI_REG_BASE 0xCD006400 -#else -#error HW model unknown. -#endif - -#define SIREG(n) ((vu32*)(SI_REG_BASE + (n))) - -#define SICOUTBUF(n) (SIREG(0x00 + (n)*12)) /* SI Channel n Output Buffer (Joy-channel n Command) (4 bytes) */ -#define SICINBUFH(i) (SIREG(0x04 + (i)*12)) /* SI Channel n Input Buffer High (Joy-channel n Buttons 1) (4 bytes) */ -#define SICINBUFL(i) (SIREG(0x08 + (i)*12)) /* SI Channel n Input Buffer Low (Joy-channel n Buttons 2) (4 bytes) */ -#define SIPOLL (SIREG(0x30)) /* SI Poll Register (4 bytes) */ -#define SICOMCSR (SIREG(0x34)) /* SI Communication Control Status Register (command) (4 bytes) */ -#define SISR (SIREG(0x38)) /* SI Status Register (4 bytes) */ -#define SIIOBUF (SIREG(0x80)) /* SI I/O buffer (access by word) (128 bytes) */ - -#define PAD_ENABLEDMASK(chan) (0x80000000 >> chan) - - - -static void SI_AwaitPendingCommands(void) { - while(*SICOMCSR & 0x1); -} - -static int SI_DetectGCKeyboard(void) { - SI_AwaitPendingCommands(); - - u32 buf[2]; - for (int i = 0; i < 4; ++i) { - SI_GetResponse(i, buf); - SI_SetCommand(i, 0x00400300); - SI_EnablePolling(PAD_ENABLEDMASK(i)); - } - SI_AwaitPendingCommands(); - - int keyboardChan = -1; - - for (int i = 0; i < 4; ++i) { - u32 type = SI_DecodeType(SI_GetType(i)); - if (type == SI_GC_KEYBOARD) - keyboardChan = i; - } - - return keyboardChan; -} - -static int SI_InitGCKeyboard(int chan) { - if (chan == -1) - return 0; - - u32 buf[2]; - - SI_GetResponse(chan, buf); - SI_SetCommand(chan, 0x00540000); - SI_EnablePolling(PAD_ENABLEDMASK(chan)); - SI_TransferCommands(); - SI_AwaitPendingCommands(); - - return 1; -} - int main(int argc, char **argv) { VIDEO_Init(); @@ -87,31 +26,27 @@ int main(int argc, char **argv) { printf("\n\nHello ...\n"); - DEBUG_Init(GDBSTUB_DEVICE_USB,1); - printf("Waiting for debugger ...\n"); - _break(); - printf("debugger connected ...\n"); + //DEBUG_Init(GDBSTUB_DEVICE_USB,1); + //printf("Waiting for debugger ...\n"); + //_break(); + //printf("debugger connected ...\n"); PAD_Init(); - int keyboardChan = SI_DetectGCKeyboard(); - printf("Keyboard located at chan %d\n", keyboardChan); + int keyboardChan = GCKB_Detect(); + printf("GC Keyboard located at chan %d\n", keyboardChan); - int keyboardEnabled = SI_InitGCKeyboard(keyboardChan); + int keyboardEnabled = GCKB_Init(keyboardChan); if (keyboardEnabled) - printf("keyboard initialized on chan %d\n", keyboardChan); + printf("GC Keyboard initialized on chan %d\n", keyboardChan); - printf("start of main loop ...\n"); + printf("Start of main loop.\nPress Start on the controller plugged into slot 1 to exit ...\n"); while(1) { if (keyboardEnabled) { - u32 buf[2]; - if (SI_GetResponse(keyboardChan, buf)) { - u8 key1 = buf[1] >> 24; - u8 key2 = (buf[1] >> 16) & 0xff; - u8 key3 = (buf[1] >> 8) & 0xff; - if (key1 | key2 | key3) - printf("keyboard data - raw: 0x%08x 0x%08x - keys: 0x%02x, 0x%02x, 0x%02x\n", - buf[0], buf[1], key1, key2, key3); + u8 keys[3]; + if (GCKB_ReadKeys(keyboardChan, keys)) { + if (keys[0] | keys[1] | keys[2]) + printf("keys pressed: 0x%02x, 0x%02x, 0x%02x\n", keys[0], keys[1], keys[2]); } } @@ -124,10 +59,6 @@ int main(int argc, char **argv) { printf("exiting ...\n"); exit(0); } - if (pressed & PAD_BUTTON_A) { - _break(); - printf("A pressed\n"); - } VIDEO_WaitVSync(); }