libdragon
|
Joybus peripheral interface. More...
Files | |
file | joybus.c |
Joybus Subsystem. | |
file | joybus_internal.h |
Joybus internal API. | |
Data Structures | |
struct | joybus_msg_t |
A message to be sent to JoyBus, with its completion callback. More... | |
Macros | |
#define | MI_INTR_SI 0x02 |
SI interrupt bit. | |
#define | MAX_JOYBUS_MSGS 8 |
Maximum number of pending joybus messages. | |
Functions | |
void | __joybus_init (void) |
Initialize the joybus subsystem. | |
void | joybus_exec_async (const void *input, void(*callback)(uint64_t *output, void *ctx), void *ctx) |
Execute an asynchronous joybus message. More... | |
void | joybus_exec (const void *input, void *output) |
Write a 64-byte block of data to the PIF and read the 64-byte result. More... | |
SI status register bit definitions | |
#define | SI_STATUS_DMA_BUSY ( 1 << 0 ) |
SI DMA busy. | |
#define | SI_STATUS_IO_BUSY ( 1 << 1 ) |
SI IO busy. | |
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.
void joybus_exec_async | ( | const void * | input, |
void(*)(uint64_t *output, void *ctx) | 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 |