#ifndef _CONTROLLER_H #define _CONTROLLER_H #include "os_internal.h" #include "rcp.h" //should go somewhere else but #define ARRLEN(x) ((s32)(sizeof(x) / sizeof(x[0]))) #define CHNL_ERR(format) (((format).rxsize & CHNL_ERR_MASK) >> 4) typedef struct { /* 0x0 */ u32 ramarray[15]; /* 0x3C */ u32 pifstatus; } OSPifRam; typedef struct { /* 0x0 */ u8 dummy; /* 0x1 */ u8 txsize; /* 0x2 */ u8 rxsize; /* 0x3 */ u8 cmd; /* 0x4 */ u16 button; /* 0x6 */ s8 stick_x; /* 0x7 */ s8 stick_y; } __OSContReadFormat; typedef struct { /* 0x0 */ u8 dummy; /* 0x1 */ u8 txsize; /* 0x2 */ u8 rxsize; /* 0x3 */ u8 cmd; /* 0x4 */ u8 typeh; /* 0x5 */ u8 typel; /* 0x6 */ u8 status; /* 0x7 */ u8 dummy1; } __OSContRequesFormat; typedef struct { /* 0x0 */ u8 txsize; /* 0x1 */ u8 rxsize; /* 0x2 */ u8 cmd; /* 0x3 */ u8 typeh; /* 0x4 */ u8 typel; /* 0x5 */ u8 status; } __OSContRequesFormatShort; typedef struct { /* 0x0 */ u8 dummy; /* 0x1 */ u8 txsize; /* 0x2 */ u8 rxsize; /* 0x3 */ u8 cmd; /* 0x4 */ u8 addrh; /* 0x5 */ u8 addrl; /* 0x6 */ u8 data[BLOCKSIZE]; /* 0x26 */ u8 datacrc; } __OSContRamReadFormat; typedef union { /* 0x0 */ struct { /* 0x0 */ u8 bank; /* 0x1 */ u8 page; } inode_t; /* 0x0 */ u16 ipage; } __OSInodeUnit; typedef struct { /* 0x0 */ u32 game_code; /* 0x4 */ u16 company_code; /* 0x6 */ __OSInodeUnit start_page; /* 0x8 */ u8 status; /* 0x9 */ s8 reserved; /* 0xA */ u16 data_sum; /* 0xC */ u8 ext_name[PFS_FILE_EXT_LEN]; /* 0x10 */ u8 game_name[PFS_FILE_NAME_LEN]; } __OSDir; typedef struct { /* 0x0 */ __OSInodeUnit inode_page[128]; } __OSInode; typedef struct { /* 0x0 */ u32 repaired; /* 0x4 */ u32 random; /* 0x8 */ u64 serial_mid; /* 0x10 */ u64 serial_low; /* 0x18 */ u16 deviceid; /* 0x1A */ u8 banks; /* 0x1B */ u8 version; /* 0x1C */ u16 checksum; /* 0x1E */ u16 inverted_checksum; } __OSPackId; typedef struct { /* 0x0 */ u8 txsize; /* 0x1 */ u8 rxsize; /* 0x2 */ u8 cmd; /* 0x3 */ u8 address; /* 0x4 */ u8 data[EEPROM_BLOCK_SIZE]; } __OSContEepromFormat; // Joybus commands //from: http://en64.shoutwiki.com/wiki/SI_Registers_Detailed#CONT_CMD_Usage #define CONT_CMD_REQUEST_STATUS 0 #define CONT_CMD_READ_BUTTON 1 #define CONT_CMD_READ_PAK 2 #define CONT_CMD_WRITE_PAK 3 #define CONT_CMD_READ_EEPROM 4 #define CONT_CMD_WRITE_EEPROM 5 #define CONT_CMD_READ36_VOICE 9 #define CONT_CMD_WRITE20_VOICE 10 #define CONT_CMD_READ2_VOICE 11 #define CONT_CMD_WRITE4_VOICE 12 #define CONT_CMD_SWRITE_VOICE 13 #define CONT_CMD_CHANNEL_RESET 0xFD #define CONT_CMD_RESET 0xFF // Bytes transmitted for each joybus command #define CONT_CMD_REQUEST_STATUS_TX 1 #define CONT_CMD_READ_BUTTON_TX 1 #define CONT_CMD_READ_PAK_TX 3 #define CONT_CMD_WRITE_PAK_TX 35 #define CONT_CMD_READ_EEPROM_TX 2 #define CONT_CMD_WRITE_EEPROM_TX 10 #define CONT_CMD_READ36_VOICE_TX 3 #define CONT_CMD_WRITE20_VOICE_TX 23 #define CONT_CMD_READ2_VOICE_TX 3 #define CONT_CMD_WRITE4_VOICE_TX 7 #define CONT_CMD_SWRITE_VOICE_TX 3 #define CONT_CMD_RESET_TX 1 // Bytes received for each joybus command #define CONT_CMD_REQUEST_STATUS_RX 3 #define CONT_CMD_READ_BUTTON_RX 4 #define CONT_CMD_READ_PAK_RX 33 #define CONT_CMD_WRITE_PAK_RX 1 #define CONT_CMD_READ_EEPROM_RX 8 #define CONT_CMD_WRITE_EEPROM_RX 1 #define CONT_CMD_READ36_VOICE_RX 37 #define CONT_CMD_WRITE20_VOICE_RX 1 #define CONT_CMD_READ2_VOICE_RX 3 #define CONT_CMD_WRITE4_VOICE_RX 1 #define CONT_CMD_SWRITE_VOICE_RX 1 #define CONT_CMD_RESET_RX 3 #define CONT_CMD_NOP 0xff #define CONT_CMD_END 0xfe //indicates end of a command #define CONT_CMD_EXE 1 //set pif ram status byte to this to do a command #define DIR_STATUS_EMPTY 0 #define DIR_STATUS_UNKNOWN 1 #define DIR_STATUS_OCCUPIED 2 // Controller accessory addresses // https://github.com/joeldipops/TransferBoy/blob/master/docs/TransferPakReference.md // Accesory detection #define CONT_ADDR_DETECT 0x8000 // Rumble #define CONT_ADDR_RUMBLE 0xC000 // Controller Pak // Transfer Pak #define CONT_ADDR_GB_POWER 0x8000 // Same as the detection address, but semantically different #define CONT_ADDR_GB_BANK 0xA000 #define CONT_ADDR_GB_STATUS 0xB000 // Addresses sent to controller accessories are in blocks, not bytes #define CONT_BLOCKS(x) ((x) / BLOCKSIZE) // Block addresses of the above #define CONT_BLOCK_DETECT CONT_BLOCKS(CONT_ADDR_DETECT) #define CONT_BLOCK_RUMBLE CONT_BLOCKS(CONT_ADDR_RUMBLE) #define CONT_BLOCK_GB_POWER CONT_BLOCKS(CONT_ADDR_GB_POWER) #define CONT_BLOCK_GB_BANK CONT_BLOCKS(CONT_ADDR_GB_BANK) #define CONT_BLOCK_GB_STATUS CONT_BLOCKS(CONT_ADDR_GB_STATUS) // Transfer pak #define GB_POWER_ON 0x84 #define GB_POWER_OFF 0xFE typedef struct { /* 0x0 */ __OSInode inode; /* 0x100 */ u8 bank; /* 0x101 */ u8 map[PFS_INODE_DIST_MAP]; } __OSInodeCache; extern s32 __osEepStatus(OSMesgQueue *, OSContStatus *); u16 __osSumcalc(u8 *ptr, int length); s32 __osIdCheckSum(u16 *ptr, u16 *csum, u16 *icsum); s32 __osRepairPackId(OSPfs *pfs, __OSPackId *badid, __OSPackId *newid); s32 __osCheckPackId(OSPfs *pfs, __OSPackId *temp); s32 __osGetId(OSPfs *pfs); s32 __osCheckId(OSPfs *pfs); s32 __osPfsRWInode(OSPfs *pfs, __OSInode *inode, u8 flag, u8 bank); s32 __osPfsSelectBank(OSPfs *pfs, u8 bank); s32 __osPfsDeclearPage(OSPfs *pfs, __OSInode *inode, int file_size_in_pages, int *first_page, u8 bank, int *decleared, int *last_page); s32 __osPfsReleasePages(OSPfs *pfs, __OSInode *inode, u8 start_page, u8 bank, __OSInodeUnit *last_page); s32 __osBlockSum(OSPfs *pfs, u8 page_no, u16 *sum, u8 bank); s32 __osContRamRead(OSMesgQueue *mq, int channel, u16 address, u8 *buffer); s32 __osContRamWrite(OSMesgQueue *mq, int channel, u16 address, u8 *buffer, int force); void __osContGetInitData(u8 *pattern, OSContStatus *data); void __osPackRequestData(u8 cmd); void __osPfsRequestData(u8 cmd); void __osPfsGetInitData(u8* pattern, OSContStatus* data); u8 __osContAddressCrc(u16 addr); u8 __osContDataCrc(u8 *data); s32 __osPfsGetStatus(OSMesgQueue *queue, int channel); extern u8 __osContLastCmd; extern OSTimer __osEepromTimer; extern OSMesg __osEepromTimerMsg; extern OSMesgQueue __osEepromTimerQ; extern OSPifRam __osEepPifRam; extern OSPifRam __osContPifRam; extern OSPifRam __osPfsPifRam; extern u8 __osMaxControllers; //some version of this almost certainly existed since there's plenty of times where it's used right before a return 0 #define ERRCK(fn) \ ret = fn; \ if (ret != 0) \ return ret #define SET_ACTIVEBANK_TO_ZERO \ if (pfs->activebank != 0) \ { \ ERRCK(__osPfsSelectBank(pfs, 0)); \ } (void)0 #define PFS_CHECK_ID \ if (__osCheckId(pfs) == PFS_ERR_NEW_PACK) \ return PFS_ERR_NEW_PACK #define PFS_CHECK_STATUS \ if ((pfs->status & PFS_INITIALIZED) == 0) \ return PFS_ERR_INVALID #define PFS_GET_STATUS \ __osSiGetAccess(); \ ret = __osPfsGetStatus(queue, channel); \ __osSiRelAccess(); \ if (ret != 0) \ return ret #endif