![]() |
libdragon
|
Joybus peripheral interface. More...
Files | |
file | joybus.c |
Joybus Subsystem. | |
file | joybus_accessory.c |
Joybus Accessory utilities. | |
file | joybus_accessory_internal.h |
Joybus accessory internal utilities. | |
file | joybus_internal.h |
Joybus internal API. | |
file | joybus.h |
Joybus Subsystem. | |
file | joybus_accessory.h |
Joybus accessory utilities. | |
Data Structures | |
union | joybus_transfer_pak_status_t |
Joybus N64 Transfer Pak Status wrapper. More... | |
Macros | |
#define | JOYBUS_ACCESSORY_TRANSFER_BANK_SIZE 0x4000 |
Size of Transfer Pak bank area in bytes. | |
#define | JOYBUS_ACCESSORY_TRANSFER_BANK_MASK 0x3FFF |
Mask for Transfer Pak bank area address. | |
#define | JOYBUS_PORT_COUNT 5 |
Count of Joybus ports. | |
#define | joybus_exec_cmd_struct(port, cmd) |
Execute a Joybus command struct synchronously. | |
Typedefs | |
typedef uint16_t | joybus_identifier_t |
Joypad Identifier type. | |
typedef void(* | joybus_callback_t) (uint64_t *out_dwords, void *ctx) |
Callback function signature for joybus_exec_async. | |
Enumerations | |
enum | joybus_accessory_io_status_t { JOYBUS_ACCESSORY_IO_STATUS_OK = 0 , JOYBUS_ACCESSORY_IO_STATUS_NO_DEVICE = -1 , JOYBUS_ACCESSORY_IO_STATUS_NO_PAK = -2 , JOYBUS_ACCESSORY_IO_STATUS_BAD_CRC = -3 } |
Joybus accessory read/write status values. More... | |
Functions | |
uint16_t | joybus_accessory_calculate_addr_checksum (uint16_t addr) |
Applies the checksum to a Joybus N64 accessory read/write address. | |
uint8_t | joybus_accessory_calculate_data_crc (const uint8_t *data) |
Calculates the CRC8 checksum for a Joybus N64 accessory read/write data block. | |
joybus_accessory_io_status_t | joybus_accessory_compare_data_crc (const uint8_t *data, uint8_t data_crc) |
Calculates the CRC8 checksum for an accessory read/write data block and compares it against the provided checksum. | |
void | joybus_accessory_read_async (int port, uint16_t addr, joybus_callback_t callback, void *ctx) |
Asynchronously perform a Joybus N64 accessory read command. | |
void | joybus_accessory_write_async (int port, uint16_t addr, const uint8_t *data, joybus_callback_t callback, void *ctx) |
Asynchronously perform a Joybus N64 accessory write command. | |
int | joybus_accessory_read (int port, uint16_t addr, uint8_t *data) |
Synchronously perform a Joybus N64 accessory read command. | |
int | joybus_accessory_write (int port, uint16_t addr, const uint8_t *data) |
Synchronously perform a Joybus N64 accessory write command. | |
void | joybus_exec_async (const void *input, joybus_callback_t callback, void *ctx) |
Execute an asynchronous joybus message. | |
void | joybus_exec (const void *input, void *output) |
Write a 64-byte block of data to the PIF and read the 64-byte result. | |
void | joybus_exec_cmd (int port, size_t send_len, size_t recv_len, const void *send_data, void *recv_data) |
Execute a Joybus command synchronously on the given port. | |
Joybus N64 accessory probe values | |
#define | JOYBUS_ACCESSORY_PROBE_ABSENT 0x00 |
Absent accessory identifier value. | |
#define | JOYBUS_ACCESSORY_PROBE_RUMBLE_PAK 0x80 |
Rumble Pak identifier value. | |
#define | JOYBUS_ACCESSORY_PROBE_BIO_SENSOR 0x81 |
Bio Sensor identifier value. | |
#define | JOYBUS_ACCESSORY_PROBE_TRANSFER_PAK_ON 0x84 |
Transfer Pak power-on identifier value. | |
#define | JOYBUS_ACCESSORY_PROBE_SNAP_STATION 0x85 |
Pokemon Snap Station identifier value. | |
#define | JOYBUS_ACCESSORY_PROBE_TRANSFER_PAK_OFF 0xFE |
Transfer Pak power-off identifier value. | |
Joybus payload sizes | |
#define | JOYBUS_BLOCK_SIZE 64 |
Size of a Joybus input/output block in bytes. | |
#define | JOYBUS_BLOCK_DWORDS ( JOYBUS_BLOCK_SIZE / sizeof(uint64_t) ) |
Size of a Joybus input/output block in double-words. | |
#define | JOYBUS_ACCESSORY_DATA_SIZE 32 |
Size of a Joybus N64 accessory read/write payload in bytes. | |
Joybus identifier values | |
#define | JOYBUS_IDENTIFIER_UNKNOWN 0x0000 |
Joybus identifier for an unknown or malfunctioning device. | |
#define | JOYBUS_IDENTIFIER_NONE 0xFFFF |
Joybus identifier for a port with no device connected. | |
#define | JOYBUS_IDENTIFIER_N64_VOICE_RECOGNITION 0x0001 |
Joybus identifier for the Nintendo 64 voice recognition peripheral (NUS-020). | |
#define | JOYBUS_IDENTIFIER_N64_RANDNET_KEYBOARD 0x0002 |
Joybus identifier for the Nintendo 64 Randnet keyboard peripheral (RND-001). | |
#define | JOYBUS_IDENTIFIER_64GB_LINK_CABLE 0x0003 |
Joybus identifier for the unreleased 64GB Link Cable. | |
#define | JOYBUS_IDENTIFIER_GBA_LINK_CABLE 0x0004 |
Joybus identifier for a Game Boy Advance Link Cable (DOL-011). | |
#define | JOYBUS_IDENTIFIER_CART_RTC 0x0010 |
Joybus identifier for cartridge-based real-time clock. | |
#define | JOYBUS_IDENTIFIER_CART_EEPROM_4KBIT 0x0080 |
Joybus identifier for cartridge-based 4Kbit EEPROM save type. | |
#define | JOYBUS_IDENTIFIER_CART_EEPROM_16KBIT 0x00C0 |
Joybus identifier for cartridge-based 16Kbit EEPROM save type. | |
#define | JOYBUS_IDENTIFIER_N64_CONTROLLER 0x0500 |
Joybus identifier for a standard Nintendo 64 controller (NUS-005). | |
#define | JOYBUS_IDENTIFIER_N64_MOUSE 0x0200 |
Joybus identifier for the Nintendo 64 mouse peripheral (NUS-017). | |
Joybus identifier bitfield for GameCube peripherals | |
Note that for GameCube peripherals, the Joybus identifier is interpreted as a bitfield rather than a single value. In particular, Wavebird controllers will return a different identifiers depending on wireless state. To identify a device that acts like a standard GameCube controller, check the JOYBUS_IDENTIFIER_MASK_PLATFORM and the JOYBUS_IDENTIFIER_MASK_GCN_CONTROLLER values. | |
#define | JOYBUS_IDENTIFIER_MASK_PLATFORM 0x1800 |
Joybus identifier platform bitfield mask. | |
#define | JOYBUS_IDENTIFIER_PLATFORM_GCN 0x0800 |
GameCube Joybus identifier platform value. | |
#define | JOYBUS_IDENTIFIER_MASK_GCN_CONTROLLER 0x0100 |
Joybus identifier GameCube standard controller flag. | |
#define | JOYBUS_IDENTIFIER_MASK_GCN_NORUMBLE 0x2000 |
Joybus identifier GameCube rumble support flag. | |
#define | JOYBUS_IDENTIFIER_MASK_GCN_WIRELESS 0x8000 |
Joybus identifier GameCube wireless flag. | |
Joybus identify status values | |
#define | JOYBUS_IDENTIFY_STATUS_ACCESSORY_MASK 0x03 |
Joybus identify status byte mask for N64 accessory presence values. | |
#define | JOYBUS_IDENTIFY_STATUS_ACCESSORY_UNSUPPORTED 0x00 |
Joybus identify status for an N64 controller that does not support accessories. | |
#define | JOYBUS_IDENTIFY_STATUS_ACCESSORY_PRESENT 0x01 |
Joybus identify status for an N64 controller with an accessory present. | |
#define | JOYBUS_IDENTIFY_STATUS_ACCESSORY_ABSENT 0x02 |
Joybus identify status for an N64 controller with no accessory present. | |
#define | JOYBUS_IDENTIFY_STATUS_ACCESSORY_CHANGED 0x03 |
Joybus identify status for an N64 controller with an accessory present that has changed since it was last identified. | |
#define | JOYBUS_IDENTIFY_STATUS_VOICE_RECOGNITON_READY 0x01 |
Joybus identify status bit for a VRU/VRS that is initialized and ready. | |
#define | JOYBUS_IDENTIFY_STATUS_COMMAND_CHECKSUM_ERROR 0x04 |
Joybus identify status bit that signifies the previous accessory command had a checksum error. | |
#define | JOYBUS_IDENTIFY_STATUS_GCN_RUMBLE_ACTIVE 0x08 |
Joybus identify status bit for GameCube controllers that indicates whether the rumble motor is currently active. | |
#define | JOYBUS_IDENTIFY_STATUS_EEPROM_BUSY 0x80 |
Joybus identify status bit for EEPROM devices that indicates a write is in-progress. | |
Joybus peripheral interface.
The Joybus subsystem is in charge of communication with all controllers, accessories, and peripherals plugged into the N64 controller ports as well as some peripherals on the cartridge. The Joybus subsystem is responsible for communicating with the serial interface (SI) registers to send commands to controllers (including Controller Paks, Rumble Paks, and Transfer Paks), the VRU, EEPROM save memory, and the cartridge-based real-time clock.
This module implements just the low-level protocol. You should use it only to implement an unsupported peripherals. Otherwise, refer to the higher-level modules such as:
For controllers: Controller Subsystem.
For EEPROM, RTC and other peripherals: Peripherals Subsystem.
Internally, the JoyBus subsystem communicates with the PIF controller via the SI DMA, via the JoyBus protocol which is a standard master/slave binary protocol. Each message of the protocol is a block of 64 bytes, and can contain multiple commands. Currently, there are no macros or functions to help composing a JoyBus message, so higher-level libraries currently hard code the binary messages.
All communications is made asynchronously because SI DMA is quite slow: its completion is bound to the PIF actually processing the data, rather than just being the memory transfer. A queue of pending JoyBus messages is kept in a ring buffer, and is then executed under interrupt when the previous SI DMA completes. The internal entry point is joybus_exec_async, that schedules a message to be sent to PIF, and calls a callback with the reply whenever it is available. A blocking API (joybus_exec) is made available for simpler usage.
union joybus_transfer_pak_status_t |
Joybus N64 Transfer Pak Status wrapper.
Type union that unpacks the raw Transfer Pak status byte to conveniently access the flags through a struct. If you prefer bitwise operations, you can use JOYBUS_TRANSFER_PAK_STATUS values as masks.
#define JOYBUS_ACCESSORY_PROBE_ABSENT 0x00 |
Absent accessory identifier value.
For Rumble Pak, Transfer Pak, and Snap Station, you must write the expected identifier to the probe address and then read it back. If the expected accessory is not connected, this value will be returned.
#define JOYBUS_ACCESSORY_PROBE_TRANSFER_PAK_ON 0x84 |
Transfer Pak power-on identifier value.
When this value is written to the probe address, the Transfer Pak will power on and respond to probe reads with this value.
If the accessory is not a Transfer Pak or the Transfer Pak is not powered on, the probe read will return the JOYBUS_ACCESSORY_PROBE_ABSENT value.
#define JOYBUS_ACCESSORY_PROBE_TRANSFER_PAK_OFF 0xFE |
Transfer Pak power-off identifier value.
When this value is written to the probe address, the Transfer Pak will power off and respond to probe reads with the JOYBUS_ACCESSORY_PROBE_ABSENT value.
#define JOYBUS_PORT_COUNT 5 |
Count of Joybus ports.
The N64 has four joypad ports, plus one additional port exposed on the cartridge connector for EEPROM and real-time clock support.
#define JOYBUS_IDENTIFIER_N64_VOICE_RECOGNITION 0x0001 |
Joybus identifier for the Nintendo 64 voice recognition peripheral (NUS-020).
Also known as VRU in North America and VRS in Japan.
#define JOYBUS_IDENTIFIER_MASK_PLATFORM 0x1800 |
Joybus identifier platform bitfield mask.
Bits 11-12 of the Joybus identifier signify the intended platform:
#define JOYBUS_IDENTIFIER_PLATFORM_GCN 0x0800 |
GameCube Joybus identifier platform value.
Bit 11 of the Joybus identifier is one for GameCube devices. Bit 12 of the Joybus identifier is zero for all known devices.
#define JOYBUS_IDENTIFIER_MASK_GCN_CONTROLLER 0x0100 |
Joybus identifier GameCube standard controller flag.
For GameCube platform devices, this bit is set if the device acts like a standard controller.
#define JOYBUS_IDENTIFIER_MASK_GCN_NORUMBLE 0x2000 |
Joybus identifier GameCube rumble support flag.
For GameCube controllers, this bit is set if the controller DOES NOT support rumble functionality.
#define JOYBUS_IDENTIFIER_MASK_GCN_WIRELESS 0x8000 |
Joybus identifier GameCube wireless flag.
For GameCube controllers, this bit is set if the controller is a wireless controller.
#define JOYBUS_IDENTIFY_STATUS_ACCESSORY_UNSUPPORTED 0x00 |
Joybus identify status for an N64 controller that does not support accessories.
Some third-party controllers incorrectly use this status to mean absence of an accessory. Therefore, this value is treated as a synonym for JOYBUS_IDENTIFY_STATUS_ACCESSORY_ABSENT.
#define joybus_exec_cmd_struct | ( | port, | |
cmd | |||
) |
Execute a Joybus command struct synchronously.
This macro is a convenience wrapper around joybus_exec_cmd that uses the send and recv fields of the struct to set the proper arguments.
This is not a stable feature of the libdragon API and should be considered experimental!
The usage of this macro will likely change as a result of the ongoing effort to integrate the multitasking kernel with asynchronous operations.
port | The Joybus port to execute the command on. | |
[in,out] | cmd | The command struct to execute with. |
typedef uint16_t joybus_identifier_t |
Joypad Identifier type.
For known values, see JOYBUS_IDENTIFIER and JOYBUS_IDENTIFIER_GCN_BITFIELD.
typedef void(* joybus_callback_t) (uint64_t *out_dwords, void *ctx) |
Callback function signature for joybus_exec_async.
Note that this function will be called under interrupt, so your callback:
Joybus accessory read/write status values.
uint16_t joybus_accessory_calculate_addr_checksum | ( | uint16_t | addr | ) |
Applies the checksum to a Joybus N64 accessory read/write address.
When reading or writing a particular address on the accessory, the command will send the top 11 bits of a 16 bit address, plus a 5 bit checksum.
addr | The address to calculate the checksum for. |
uint8_t joybus_accessory_calculate_data_crc | ( | const uint8_t * | data | ) |
Calculates the CRC8 checksum for a Joybus N64 accessory read/write data block.
Uses a CRC8 algorithm with a seed of 0x00 and a polynomial of 0x85.
[in] | data | The 32-byte accessory read/write data block |
joybus_accessory_io_status_t joybus_accessory_compare_data_crc | ( | const uint8_t * | data, |
uint8_t | data_crc | ||
) |
Calculates the CRC8 checksum for an accessory read/write data block and compares it against the provided checksum.
[in] | data | The 32-byte accessory read/write data block |
data_crc | The CRC8 checksum to compare against |
JOYBUS_ACCESSORY_IO_STATUS_OK | The checksums match. |
JOYBUS_ACCESSORY_IO_STATUS_NO_PAK | The checksum indicates that no accessory is present. |
JOYBUS_ACCESSORY_IO_STATUS_BAD_CRC | The data checksum does not match the provided checksum. |
void joybus_accessory_read_async | ( | int | port, |
uint16_t | addr, | ||
joybus_callback_t | callback, | ||
void * | ctx | ||
) |
Asynchronously perform a Joybus N64 accessory read command.
port | The controller port of the accessory to read from. |
addr | The accessory address to read from. |
callback | A function pointer to call when the operation completes. |
ctx | A user data pointer to pass into the callback function. |
void joybus_accessory_write_async | ( | int | port, |
uint16_t | addr, | ||
const uint8_t * | data, | ||
joybus_callback_t | callback, | ||
void * | ctx | ||
) |
Asynchronously perform a Joybus N64 accessory write command.
port | The controller port of the accessory to write to. | |
addr | The accessory address to write to. | |
[in] | data | The data to write to the accessory. |
callback | A function pointer to call when the operation completes. | |
ctx | A user data pointer to pass into the callback function. |
int joybus_accessory_read | ( | int | port, |
uint16_t | addr, | ||
uint8_t * | data | ||
) |
Synchronously perform a Joybus N64 accessory read command.
port | The controller port of the accessory to read from. | |
addr | The accessory address to start reading from. | |
[out] | data | The 32 bytes of data that was read from the accessory. |
JOYBUS_ACCESSORY_IO_STATUS_OK | The data was read successfully. |
JOYBUS_ACCESSORY_IO_STATUS_NO_PAK | No accessory is present. |
JOYBUS_ACCESSORY_IO_STATUS_BAD_CRC | The data was not read successfully. |
int joybus_accessory_write | ( | int | port, |
uint16_t | addr, | ||
const uint8_t * | data | ||
) |
Synchronously perform a Joybus N64 accessory write command.
port | The controller port of the accessory to write to. | |
addr | The accessory address to start writing to. | |
[in] | data | The 32 bytes of data to write to the accessory. |
JOYBUS_ACCESSORY_IO_STATUS_OK | The data was written successfully. |
JOYBUS_ACCESSORY_IO_STATUS_NO_PAK | No accessory is present. |
JOYBUS_ACCESSORY_IO_STATUS_BAD_CRC | The data was not written successfully. |
void joybus_exec_async | ( | const void * | input, |
joybus_callback_t | callback, | ||
void * | ctx | ||
) |
Execute an asynchronous joybus message.
This function executes an asynchronous joybus protocol exchange, sending a message block (input), and receiving a reply (output). The message is sent in background and a completion function "callback" is called when the output is ready to be processed.
It is possible to schedule multiple joybus messages by calling this function multiple times. They will be automatically executed in order. The maximum number of pending messages at any given time is MAX_JOYBUS_MSGS.
[in] | input | The input block (must be of JOYBUS_BLOCK_SIZE bytes). No specific alignment is required for this data block. |
[in] | callback | A callback completion function that will be called when the joybus command is finished. The function will receive a pointer to the output buffer and the opaque pointer to the callback's context. Can be NULL if no callback is required. |
[in] | ctx | Context opaque pointer to pass to the callback. Can be NULL if no context is required. |
void joybus_exec | ( | const void * | input, |
void * | output | ||
) |
Write a 64-byte block of data to the PIF and read the 64-byte result.
This function is not a stable feature of the libdragon API and should be considered experimental!
The usage of this function will likely change as a result of the ongoing effort to integrate the multitasking kernel with asynchronous operations.
[in] | input | Source buffer for the input block to send to the PIF |
[out] | output | Destination buffer to place the output block from the PIF |
|
inline |
Execute a Joybus command synchronously on the given port.
For convenience, there is a joybus_exec_cmd_struct macro that uses the send and recv fields of a command struct to call this function with the proper send_len and recv_len arguments.
This function only sends a single command to a single port. For sending a command to multiple ports simultaneously, use joybus_exec instead.
For reading controllers, use the Joypad Subsystem instead.
This function is not a stable feature of the libdragon API and should be considered experimental!
The usage of this function will likely change as a result of the ongoing effort to integrate the multitasking kernel with asynchronous operations.
port | The Joybus port (0-4) to send the command to. | |
send_len | Number of bytes in the send_data request payload (including the command ID). | |
recv_len | Number of bytes in the recv_data response payload. | |
[in] | send_data | Buffer of send_len bytes to send to the Joybus device (including the command ID byte). |
[out] | recv_data | Buffer of recv_len bytes for the reply from the Joybus device. |