cc3dsfs/source/CaptureDeviceSpecific/ISNitro/usb_is_nitro_communications.cpp
2024-12-03 06:38:33 +01:00

557 lines
22 KiB
C++

#include "frontend.hpp"
#include "usb_is_nitro_communications.hpp"
#include "usb_is_nitro_libusb.hpp"
#include "usb_is_nitro_is_driver.hpp"
#include <libusb.h>
#include <cstring>
#include <thread>
#include <chrono>
#include <iostream>
// Code based off of Gericom's sample code. Distributed under the MIT License. Copyright (c) 2024 Gericom
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
#define USB_PACKET_LIMIT 0x2000
#define REG_USB_DMA_CONTROL_2 0x0C000028
#define REG_USB_BIU_CONTROL_2 0x0C0000A4
enum is_nitro_packet_emulator_dir {
IS_NITRO_PACKET_EMU_DIR_WRITE = 0x10,
IS_NITRO_PACKET_EMU_DIR_READ = 0x11
};
enum is_nitro_packet_capture_dir {
IS_NITRO_PACKET_CAP_DIR_WRITE = 0x00,
IS_NITRO_PACKET_CAP_DIR_READ = 0x01
};
enum is_nitro_packet_type {
IS_NITRO_PACKET_TYPE_COMMAND = 0,
IS_NITRO_PACKET_TYPE_EMU_MEMORY = 1,
IS_NITRO_EMULATOR_PACKET_TYPE_AGB_SRAM = 2,
IS_NITRO_CAPTURE_PACKET_TYPE_DMA_CONTROL = 2,
IS_NITRO_PACKET_TYPE_CAPTURE = 3,
IS_NITRO_PACKET_TYPE_AGB_CART_ROM = 4,
IS_NITRO_PACKET_TYPE_AGB_BUS2 = 5
};
enum is_nitro_emulator_command {
IS_NITRO_EMU_CMD_GET_SERIAL = 0x13,
IS_NITRO_EMU_CMD_READ_NEC_MEM = 0x17,
IS_NITRO_EMU_CMD_WRITE_NEC_MEM = 0x24,
IS_NITRO_EMU_CMD_SET_READ_NEC_MEM = 0x25,
IS_NITRO_EMU_CMD_FULL_HARDWARE_RESET = 0x81,
IS_NITRO_EMU_CMD_CPU_RESET = 0x8A,
IS_NITRO_EMU_CMD_AD = 0xAD,
};
enum is_nitro_capture_command {
IS_NITRO_CAP_CMD_ENABLE_CAP = 0x00,
IS_NITRO_CAP_CMD_GET_SERIAL = 0x03,
IS_NITRO_CAP_CMD_SET_FWD_RATE = 0x12,
IS_NITRO_CAP_CMD_SET_FWD_MODE = 0x13,
IS_NITRO_CAP_CMD_SET_FWD_COLOURS = 0x14,
IS_NITRO_CAP_CMD_SET_FWD_FRAMES = 0x15,
IS_NITRO_CAP_CMD_GET_DEBUG_STATE = 0x18,
IS_NITRO_CAP_CMD_SET_RESTART_FULL = 0x18,
IS_NITRO_CAP_CMD_GET_LID_STATE = 0x19,
IS_NITRO_CAP_CMD_SET_FWD_RESTART = 0x1C,
IS_NITRO_CAP_CMD_SET_RESET_CPU_ON = 0x21,
IS_NITRO_CAP_CMD_SET_RESET_CPU_OFF = 0x22,
};
enum is_nitro_emulator_forward_bits {
IS_NITRO_EMULATOR_FORWARD_ENABLE_BIT = 0,
IS_NITRO_EMULATOR_FORWARD_COUNTER_RESTART_BIT = 1,
};
enum is_nitro_capture_forward_bits {
IS_NITRO_CAPTURE_FORWARD_COUNTER_RESTART_BIT = 0,
};
#pragma pack(push, 1)
struct PACKED is_nitro_nec_packet_header {
uint8_t command;
uint8_t unit_size;
uint16_t count;
uint32_t address;
};
struct PACKED is_nitro_packet_header {
uint16_t command;
uint8_t direction;
uint8_t type;
uint32_t address;
uint32_t length;
uint32_t padding;
};
#pragma pack(pop)
static const is_nitro_usb_device usb_is_nitro_emu_rare_desc = {
.name = "ISNEr", .long_name = "IS Nitro Emulator(R)",
.vid = 0x0f6e, .pid = 0x0400,
.default_config = 1, .default_interface = 0,
.bulk_timeout = 500,
.ep2_in = 2 | LIBUSB_ENDPOINT_IN, .ep1_out = 1 | LIBUSB_ENDPOINT_OUT,
.product_id = 2, .manufacturer_id = 1, .is_capture = false
};
static const is_nitro_usb_device usb_is_nitro_emu_common_desc = {
.name = "ISNE", .long_name = "IS Nitro Emulator",
.vid = 0x0f6e, .pid = 0x0404,
.default_config = 1, .default_interface = 0,
.bulk_timeout = 500,
.ep2_in = 2 | LIBUSB_ENDPOINT_IN, .ep1_out = 1 | LIBUSB_ENDPOINT_OUT,
.product_id = 2, .manufacturer_id = 1, .is_capture = false
};
static const is_nitro_usb_device usb_is_nitro_cap_desc = {
.name = "ISNC", .long_name = "IS Nitro Capture",
.vid = 0x0f6e, .pid = 0x0403,
.default_config = 1, .default_interface = 0,
.bulk_timeout = 500,
.ep2_in = 2 | LIBUSB_ENDPOINT_IN, .ep1_out = 1 | LIBUSB_ENDPOINT_OUT,
.product_id = 2, .manufacturer_id = 1, .is_capture = true
};
static const is_nitro_usb_device* all_usb_is_nitro_devices_desc[] = {
&usb_is_nitro_emu_rare_desc,
&usb_is_nitro_emu_common_desc,
&usb_is_nitro_cap_desc,
};
int GetNumISNitroDesc() {
return sizeof(all_usb_is_nitro_devices_desc) / sizeof(all_usb_is_nitro_devices_desc[0]);
}
const is_nitro_usb_device* GetISNitroDesc(int index) {
if((index < 0) || (index >= GetNumISNitroDesc()))
index = 0;
return all_usb_is_nitro_devices_desc[index];
}
static void fix_endianness_header(is_nitro_packet_header* header) {
header->command = to_le(header->command);
header->address = to_le(header->address);
header->length = to_le(header->length);
}
static void fix_endianness_header(is_nitro_nec_packet_header* header) {
header->count = to_le(header->count);
header->address = to_le(header->address);
}
// Write to bulk endpoint. Returns libusb error code
static int bulk_out(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t *buf, int length, int *transferred) {
if(handlers->usb_handle)
return is_nitro_libusb_bulk_out(handlers, usb_device_desc, buf, length, transferred);
return is_driver_bulk_out(handlers, usb_device_desc, buf, length, transferred);
}
// Read from bulk endpoint. Returns libusb error code
static int bulk_in(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t *buf, int length, int *transferred) {
if(handlers->usb_handle)
return is_nitro_libusb_bulk_in(handlers, usb_device_desc, buf, length, transferred);
return is_driver_bulk_in(handlers, usb_device_desc, buf, length, transferred);
}
// Read from bulk endpoint. Returns libusb error code
static void bulk_in_async(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t *buf, int length, isn_async_callback_data* cb_data) {
if(handlers->usb_handle)
return is_nitro_libusb_async_in_start(handlers, usb_device_desc, buf, length, cb_data);
is_drive_async_in_start(handlers, usb_device_desc, buf, length, cb_data);
}
static int SendWritePacket(is_nitro_device_handlers* handlers, uint16_t command, is_nitro_packet_type type, uint32_t address, uint8_t* buf, int length, const is_nitro_usb_device* device_desc, bool expect_result = true) {
is_nitro_packet_header header;
bool append_mode = true;
if(device_desc->is_capture)
append_mode = false;
uint8_t single_usb_packet[USB_PACKET_LIMIT];
int single_packet_covered_size = USB_PACKET_LIMIT - sizeof(header);
if(!append_mode)
single_packet_covered_size = USB_PACKET_LIMIT;
int num_iters = (length + single_packet_covered_size - 1) / single_packet_covered_size;
if(!num_iters)
num_iters = 1;
for(int i = 0; i < num_iters; i++) {
int transfer_size = length - (i * single_packet_covered_size);
if(transfer_size > single_packet_covered_size)
transfer_size = single_packet_covered_size;
uint8_t packet_direction = IS_NITRO_PACKET_EMU_DIR_WRITE;
if(device_desc->is_capture)
packet_direction = IS_NITRO_PACKET_CAP_DIR_WRITE;
header.command = command;
header.direction = packet_direction;
header.type = type;
header.address = address;
header.length = transfer_size;
header.padding = 0;
fix_endianness_header(&header);
int ret = 0;
int num_bytes = 0;
for(int j = 0; j < sizeof(is_nitro_packet_header); j++)
single_usb_packet[j] = ((uint8_t*)&header)[j];
if(append_mode && (buf != NULL)) {
for(int j = 0; j < transfer_size; j++)
single_usb_packet[sizeof(is_nitro_packet_header) + j] = buf[(i * single_packet_covered_size) + j];
ret = bulk_out(handlers, device_desc, single_usb_packet, transfer_size + sizeof(is_nitro_packet_header), &num_bytes);
}
else {
int header_bytes = 0;
ret = bulk_out(handlers, device_desc, single_usb_packet, sizeof(is_nitro_packet_header), &header_bytes);
if(ret < 0)
return ret;
if(header_bytes != sizeof(is_nitro_packet_header))
return LIBUSB_ERROR_INTERRUPTED;
if((buf != NULL) && (transfer_size > 0))
ret = bulk_out(handlers, device_desc, &buf[(i * single_packet_covered_size)], transfer_size, &num_bytes);
num_bytes += header_bytes;
}
if(ret < 0)
return ret;
if(num_bytes != (transfer_size + sizeof(is_nitro_packet_header)))
return LIBUSB_ERROR_INTERRUPTED;
}
if(device_desc->is_capture && expect_result) {
uint8_t status[16];
int status_bytes = 0;
int ret = bulk_in(handlers, device_desc, status, sizeof(status), &status_bytes);
if(ret < 0)
return ret;
if(status_bytes != sizeof(status))
return LIBUSB_ERROR_INTERRUPTED;
if(status[0] != 1)
return LIBUSB_ERROR_OTHER;
}
return LIBUSB_SUCCESS;
}
static int SendReadPacket(is_nitro_device_handlers* handlers, uint16_t command, is_nitro_packet_type type, uint32_t address, uint8_t* buf, int length, const is_nitro_usb_device* device_desc, bool expect_result = true) {
is_nitro_packet_header header;
int single_packet_covered_size = USB_PACKET_LIMIT;
int num_iters = (length + single_packet_covered_size - 1) / single_packet_covered_size;
if(num_iters == 0)
num_iters = 1;
for(int i = 0; i < num_iters; i++) {
int transfer_size = length - (i * single_packet_covered_size);
if(transfer_size > single_packet_covered_size)
transfer_size = single_packet_covered_size;
uint8_t packet_direction = IS_NITRO_PACKET_EMU_DIR_READ;
if(device_desc->is_capture)
packet_direction = IS_NITRO_PACKET_CAP_DIR_READ;
header.command = command;
header.direction = packet_direction;
header.type = type;
header.address = address;
header.length = transfer_size;
header.padding = 0;
fix_endianness_header(&header);
int num_bytes = 0;
int ret = bulk_out(handlers, device_desc, (uint8_t*)&header, sizeof(is_nitro_packet_header), &num_bytes);
if(ret < 0)
return ret;
if(num_bytes != sizeof(is_nitro_packet_header))
return LIBUSB_ERROR_INTERRUPTED;
if(buf != NULL) {
ret = bulk_in(handlers, device_desc, buf + (i * single_packet_covered_size), transfer_size, &num_bytes);
if(ret < 0)
return ret;
if(num_bytes != transfer_size)
return LIBUSB_ERROR_INTERRUPTED;
}
}
if(device_desc->is_capture && expect_result) {
uint8_t status[16];
int status_bytes = 0;
int ret = bulk_in(handlers, device_desc, status, sizeof(status), &status_bytes);
if(ret < 0)
return ret;
if(status_bytes != sizeof(status))
return LIBUSB_ERROR_INTERRUPTED;
if(status[0] != 1)
return LIBUSB_ERROR_OTHER;
}
return LIBUSB_SUCCESS;
}
int SendReadCommand(is_nitro_device_handlers* handlers, uint16_t command, uint8_t* buf, int length, const is_nitro_usb_device* device_desc) {
return SendReadPacket(handlers, command, IS_NITRO_PACKET_TYPE_COMMAND, 0, buf, length, device_desc);
}
int SendWriteCommand(is_nitro_device_handlers* handlers, uint16_t command, uint8_t* buf, int length, const is_nitro_usb_device* device_desc) {
return SendWritePacket(handlers, command, IS_NITRO_PACKET_TYPE_COMMAND, 0, buf, length, device_desc);
}
int SendReadCommandU32(is_nitro_device_handlers* handlers, uint16_t command, uint32_t* out, const is_nitro_usb_device* device_desc) {
uint32_t buffer;
int ret = SendReadCommand(handlers, command, (uint8_t*)&buffer, sizeof(uint32_t), device_desc);
if(ret < 0)
return ret;
*out = from_le(buffer);
return 0;
}
int SendWriteCommandU32(is_nitro_device_handlers* handlers, uint16_t command, uint32_t value, const is_nitro_usb_device* device_desc) {
uint32_t buffer = to_le(value);
return SendWriteCommand(handlers, command, (uint8_t*)&buffer, sizeof(uint32_t), device_desc);
}
int GetDeviceSerial(is_nitro_device_handlers* handlers, uint8_t* buf, const is_nitro_usb_device* device_desc) {
if(device_desc->is_capture)
return SendReadCommand(handlers, IS_NITRO_CAP_CMD_GET_SERIAL, buf, IS_NITRO_REAL_SERIAL_NUMBER_SIZE, device_desc);
return SendReadCommand(handlers, IS_NITRO_EMU_CMD_GET_SERIAL, buf, IS_NITRO_REAL_SERIAL_NUMBER_SIZE, device_desc);
}
int ReadNecMem(is_nitro_device_handlers* handlers, uint32_t address, uint8_t unit_size, uint8_t* buf, int count, const is_nitro_usb_device* device_desc) {
is_nitro_nec_packet_header header;
header.command = IS_NITRO_EMU_CMD_SET_READ_NEC_MEM;
header.unit_size = unit_size;
header.count = count;
header.address = address;
fix_endianness_header(&header);
int ret = SendWriteCommand(handlers, header.command, (uint8_t*)&header, sizeof(is_nitro_nec_packet_header), device_desc);
if(ret < 0)
return ret;
return SendReadCommand(handlers, IS_NITRO_EMU_CMD_READ_NEC_MEM, buf, count * unit_size, device_desc);
}
int ReadNecMemU16(is_nitro_device_handlers* handlers, uint32_t address, uint16_t* out, const is_nitro_usb_device* device_desc) {
uint16_t buffer;
int ret = ReadNecMem(handlers, address, 2, (uint8_t*)&buffer, 1, device_desc);
if(ret < 0)
return ret;
*out = from_le(buffer);
return 0;
}
int ReadNecMemU32(is_nitro_device_handlers* handlers, uint32_t address, uint32_t* out, const is_nitro_usb_device* device_desc) {
uint32_t buffer;
int ret = ReadNecMem(handlers, address, 2, (uint8_t*)&buffer, 2, device_desc);
if(ret < 0)
return ret;
*out = from_le(buffer);
return 0;
}
int WriteNecMem(is_nitro_device_handlers* handlers, uint32_t address, uint8_t unit_size, uint8_t* buf, int count, const is_nitro_usb_device* device_desc) {
uint8_t* buffer = new uint8_t[(count * unit_size) + sizeof(is_nitro_nec_packet_header)];
is_nitro_nec_packet_header header;
header.command = IS_NITRO_EMU_CMD_WRITE_NEC_MEM;
header.unit_size = unit_size;
header.count = count;
header.address = address;
fix_endianness_header(&header);
for(int i = 0; i < sizeof(is_nitro_nec_packet_header); i++)
buffer[i] = ((uint8_t*)&header)[i];
for(int i = 0; i < count * unit_size; i++)
buffer[i + sizeof(is_nitro_nec_packet_header)] = buf[i];
int ret = SendWriteCommand(handlers, header.command, buffer, (count * unit_size) + sizeof(is_nitro_nec_packet_header), device_desc);
delete []buffer;
return ret;
}
int WriteNecMemU16(is_nitro_device_handlers* handlers, uint32_t address, uint16_t value, const is_nitro_usb_device* device_desc) {
uint16_t buffer = to_le(value);
return WriteNecMem(handlers, address, 2, (uint8_t*)&buffer, 1, device_desc);
}
int WriteNecMemU32(is_nitro_device_handlers* handlers, uint32_t address, uint32_t value, const is_nitro_usb_device* device_desc) {
uint32_t buffer = to_le(value);
return WriteNecMem(handlers, address, 2, (uint8_t*)&buffer, 2, device_desc);
}
int DisableLca2(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc) {
if(device_desc->is_capture)
return LIBUSB_SUCCESS;
int ret = WriteNecMemU16(handlers, 0x00805180, 0, device_desc);
if(ret < 0)
return ret;
ret = WriteNecMemU16(handlers, 0x0F84000A, 1, device_desc);
if(ret < 0)
return ret;
//SleepBetweenTransfers(handlers, 2000);
return WriteNecMemU16(handlers, 0x0F84000A, 0, device_desc);
}
int StartUsbCaptureDma(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc) {
if(!device_desc->is_capture) {
int ret = WriteNecMemU16(handlers, REG_USB_DMA_CONTROL_2, 2, device_desc);
if(ret < 0)
return ret;
return WriteNecMemU16(handlers, REG_USB_BIU_CONTROL_2, 1, device_desc);
}
return SendReadPacket(handlers, IS_NITRO_CAP_CMD_ENABLE_CAP, IS_NITRO_CAPTURE_PACKET_TYPE_DMA_CONTROL, 0, NULL, 1, device_desc, false);
}
int StopUsbCaptureDma(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc) {
if(!device_desc->is_capture) {
int ret = WriteNecMemU16(handlers, REG_USB_DMA_CONTROL_2, 0, device_desc);
if(ret < 0)
return ret;
return WriteNecMemU16(handlers, REG_USB_BIU_CONTROL_2, 0, device_desc);
}
return SendReadPacket(handlers, IS_NITRO_CAP_CMD_ENABLE_CAP, IS_NITRO_CAPTURE_PACKET_TYPE_DMA_CONTROL, 0, NULL, 0, device_desc);
}
int SetForwardFrameCount(is_nitro_device_handlers* handlers, uint16_t count, const is_nitro_usb_device* device_desc) {
if(!count)
return LIBUSB_ERROR_INTERRUPTED;
count -= 1;
if(!device_desc->is_capture)
return WriteNecMemU32(handlers, 0x0800000C, (count >> 8) | ((count & 0xFF) << 16), device_desc);
return SendWriteCommandU32(handlers, IS_NITRO_CAP_CMD_SET_FWD_FRAMES, count, device_desc);
}
int SetForwardFramePermanent(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc) {
return SetForwardFrameCount(handlers, 0x4001, device_desc);
}
int GetFrameCounter(is_nitro_device_handlers* handlers, uint16_t* out, const is_nitro_usb_device* device_desc) {
if(device_desc->is_capture) {
*out = 0;
return LIBUSB_SUCCESS;
}
uint32_t counter = 0;
int ret = ReadNecMemU32(handlers, 0x08000028, &counter, device_desc);
if(ret < 0)
return ret;
*out = (counter & 0xFF) | ((counter & 0xFF0000) >> 8);
return ret;
}
int UpdateFrameForwardConfig(is_nitro_device_handlers* handlers, is_nitro_forward_config_values_colors colors, is_nitro_forward_config_values_screens screens, is_nitro_forward_config_values_rate rate, const is_nitro_usb_device* device_desc) {
if(!device_desc->is_capture)
return WriteNecMemU16(handlers, 0x0800000A, ((colors & 1) << 4) | ((screens & 3) << 2) | ((rate & 3) << 0), device_desc);
int ret = SendWriteCommandU32(handlers, IS_NITRO_CAP_CMD_SET_FWD_RATE, rate & 3, device_desc);
if(ret < 0)
return ret;
ret = SendWriteCommandU32(handlers, IS_NITRO_CAP_CMD_SET_FWD_MODE, screens & 3, device_desc);
if(ret < 0)
return ret;
return SendWriteCommandU32(handlers, IS_NITRO_CAP_CMD_SET_FWD_COLOURS, colors & 1, device_desc);
}
int UpdateFrameForwardEnable(is_nitro_device_handlers* handlers, bool enable, bool restart, const is_nitro_usb_device* device_desc) {
uint32_t value = 0;
if(!device_desc->is_capture) {
if(enable)
value |= (1 << IS_NITRO_EMULATOR_FORWARD_ENABLE_BIT);
if(restart)
value |= (1 << IS_NITRO_EMULATOR_FORWARD_COUNTER_RESTART_BIT);
return WriteNecMemU16(handlers, 0x08000008, value, device_desc);
}
if(restart)
value |= (1 << IS_NITRO_CAPTURE_FORWARD_COUNTER_RESTART_BIT);
return SendWriteCommandU32(handlers, IS_NITRO_CAP_CMD_SET_FWD_RESTART, value, device_desc);
}
int ReadLidState(is_nitro_device_handlers* handlers, bool* out, const is_nitro_usb_device* device_desc) {
uint32_t flags = 0;
if(device_desc->is_capture) {
int ret = SendReadCommandU32(handlers, IS_NITRO_CAP_CMD_GET_LID_STATE, &flags, device_desc);
*out = (flags & 1) ? true : false;
return ret;
}
int ret = ReadNecMemU32(handlers, 0x08000000, &flags, device_desc);
if(ret < 0)
return ret;
*out = (flags & 2) ? true : false;
return ret;
}
int ReadDebugButtonState(is_nitro_device_handlers* handlers, bool* out, const is_nitro_usb_device* device_desc) {
uint32_t flags = 0;
if(device_desc->is_capture) {
int ret = SendReadCommandU32(handlers, IS_NITRO_CAP_CMD_GET_DEBUG_STATE, &flags, device_desc);
*out = (flags & 1) ? true : false;
return ret;
}
int ret = ReadNecMemU32(handlers, 0x08000000, &flags, device_desc);
if(ret < 0)
return ret;
*out = (flags & 1) ? true : false;
return ret;
}
int ReadPowerButtonState(is_nitro_device_handlers* handlers, bool* out, const is_nitro_usb_device* device_desc) {
return ReadDebugButtonState(handlers, out, device_desc);
}
static int ResetCPUEmulatorGeneral(is_nitro_device_handlers* handlers, bool on, const is_nitro_usb_device* device_desc) {
uint8_t data[] = {IS_NITRO_EMU_CMD_CPU_RESET, 0, (uint8_t)(on ? 1 : 0), 0};
return SendWriteCommand(handlers, IS_NITRO_EMU_CMD_CPU_RESET, data, sizeof(data), device_desc);
}
int ResetCPUStart(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc) {
if(device_desc->is_capture)
return SendWriteCommand(handlers, IS_NITRO_CAP_CMD_SET_RESET_CPU_ON, NULL, 0, device_desc);
return ResetCPUEmulatorGeneral(handlers, true, device_desc);
}
int ResetCPUEnd(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc) {
if(device_desc->is_capture)
return SendWriteCommand(handlers, IS_NITRO_CAP_CMD_SET_RESET_CPU_OFF, NULL, 0, device_desc);
return ResetCPUEmulatorGeneral(handlers, false, device_desc);
}
int ResetFullHardware(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc) {
if(device_desc->is_capture)
return SendWriteCommand(handlers, IS_NITRO_CAP_CMD_SET_RESTART_FULL, NULL, 0, device_desc);
uint8_t data[] = {IS_NITRO_EMU_CMD_FULL_HARDWARE_RESET, 0xF2};
return SendWriteCommand(handlers, IS_NITRO_EMU_CMD_FULL_HARDWARE_RESET, data, sizeof(data), device_desc);
}
int ReadFrame(is_nitro_device_handlers* handlers, uint8_t* buf, int length, const is_nitro_usb_device* device_desc) {
// Maybe making this async would be better for lower end hardware...
int num_bytes = 0;
int ret = bulk_in(handlers, device_desc, buf, length, &num_bytes);
if(num_bytes != length)
return LIBUSB_ERROR_INTERRUPTED;
return ret;
}
void ReadFrameAsync(is_nitro_device_handlers* handlers, uint8_t* buf, int length, const is_nitro_usb_device* device_desc, isn_async_callback_data* cb_data) {
return bulk_in_async(handlers, device_desc, buf, length, cb_data);
}
void CloseAsyncRead(is_nitro_device_handlers* handlers, isn_async_callback_data* cb_data) {
if(handlers->usb_handle)
return is_nitro_libusb_cancell_callback(cb_data);
return is_nitro_is_driver_cancel_callback(cb_data);
}
void SetupISNitroAsyncThread(is_nitro_device_handlers* handlers, void* user_data, std::thread* thread_ptr, bool* keep_going, ConsumerMutex* is_data_ready) {
if(handlers->usb_handle)
return is_nitro_libusb_start_thread(thread_ptr, keep_going);
return is_nitro_is_driver_start_thread(thread_ptr, keep_going, (ISNitroCaptureReceivedData*)user_data, handlers, is_data_ready);
}
void EndISNitroAsyncThread(is_nitro_device_handlers* handlers, void* user_data, std::thread* thread_ptr, bool* keep_going, ConsumerMutex* is_data_ready) {
if(handlers->usb_handle)
return is_nitro_libusb_close_thread(thread_ptr, keep_going);
return is_nitro_is_driver_close_thread(thread_ptr, keep_going, (ISNitroCaptureReceivedData*)user_data);
}