Implement Old DS Nisetro Capture

This commit is contained in:
Lorenzooone
2025-01-25 22:18:26 +01:00
parent d69c2ca31e
commit 875a6105b1
16 changed files with 2068 additions and 7 deletions

View File

@@ -10,10 +10,11 @@ set(N3DSXL_LOOPY_SUPPORT 1)
set(NEW_DS_LOOPY_SUPPORT 1)
set(IS_DEVICES_SUPPORT 1)
set(OLD_DS_3DS_LOOPY_SUPPORT 1)
set(CYPRESS_NISETRO_SUPPORT 1)
set(USE_FTD2XX_FOR_NEW_DS_LOOPY ${NEW_DS_LOOPY_SUPPORT})
set(USE_LIBFTDI_FOR_NEW_DS_LOOPY ${NEW_DS_LOOPY_SUPPORT})
set(USE_LIBUSB_SUPPORT ${IS_DEVICES_SUPPORT} OR ${OLD_DS_3DS_LOOPY_SUPPORT} OR ${USE_LIBFTDI_FOR_NEW_DS_LOOPY})
set(USE_LIBUSB_SUPPORT ${IS_DEVICES_SUPPORT} OR ${OLD_DS_3DS_LOOPY_SUPPORT} OR ${USE_LIBFTDI_FOR_NEW_DS_LOOPY} OR ${CYPRESS_NISETRO_SUPPORT})
if(NOT (${CMAKE_SYSTEM_NAME} STREQUAL "Windows"))
#Performance outside of Windows is very bad for the official drivers...
set(USE_FTD2XX_FOR_NEW_DS_LOOPY 0)
@@ -293,6 +294,7 @@ set(EXTRA_DEPENDENCIES "")
set(SOURCE_CPP_DEVICE_FILES_BASE_PATH "source/CaptureDeviceSpecific")
set(SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH "${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/ISDevices")
set(SOURCE_CPP_FTD2_FILES_BASE_PATH "${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/DSCapture_FTD2")
set(SOURCE_CPP_CYPRESS_NISETRO_DEVICES_FILES_BASE_PATH "${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/Nisetro")
if(N3DSXL_LOOPY_SUPPORT)
list(APPEND FETCH_CONTENT_MAKE_AVAILABLE_LIBRARIES FTD3XX)
list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/3dscapture_ftd3.cpp)
@@ -328,6 +330,14 @@ if(OLD_DS_3DS_LOOPY_SUPPORT)
list(APPEND EXTRA_CXX_FLAGS "-DUSE_DS_3DS_USB")
endif()
endif()
if(CYPRESS_NISETRO_SUPPORT)
list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_CYPRESS_NISETRO_DEVICES_FILES_BASE_PATH}/cypress_nisetro_driver_comms.cpp ${SOURCE_CPP_CYPRESS_NISETRO_DEVICES_FILES_BASE_PATH}/cypress_nisetro_libusb_comms.cpp ${SOURCE_CPP_CYPRESS_NISETRO_DEVICES_FILES_BASE_PATH}/cypress_nisetro_communications.cpp ${SOURCE_CPP_CYPRESS_NISETRO_DEVICES_FILES_BASE_PATH}/cypress_nisetro_acquisition.cpp ${TOOLS_DATA_DIR}/nisetro_ds_fw.cpp)
if(MSVC)
list(APPEND EXTRA_CXX_FLAGS "/DUSE_CYNI_USB")
else()
list(APPEND EXTRA_CXX_FLAGS "-DUSE_CYNI_USB")
endif()
endif()
if(NEW_DS_LOOPY_SUPPORT)
list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_FTD2_FILES_BASE_PATH}/dscapture_ftd2_shared.cpp ${SOURCE_CPP_FTD2_FILES_BASE_PATH}/dscapture_ftd2_compatibility.cpp ${TOOLS_DATA_DIR}/ftd2_ds2_fw_1.cpp ${TOOLS_DATA_DIR}/ftd2_ds2_fw_2.cpp)
if(MSVC)
@@ -475,9 +485,9 @@ execute_process(COMMAND ${CMAKE_COMMAND} --build ${TOOLS_DATA_DIR})
set(OUTPUT_NAME cc3dsfs)
if(MSVC)
set_source_files_properties(source/conversions.cpp PROPERTIES COMPILE_OPTIONS "/O2")
set_source_files_properties(source/conversions.cpp PROPERTIES COMPILE_OPTIONS "$<$<CONFIG:Release>:/O2>")
else()
set_source_files_properties(source/conversions.cpp PROPERTIES COMPILE_OPTIONS "-O3")
set_source_files_properties(source/conversions.cpp PROPERTIES COMPILE_OPTIONS "$<$<CONFIG:Release>:-O3>")
endif()
add_executable(${OUTPUT_NAME} source/cc3dsfs.cpp source/utils.cpp source/audio_data.cpp source/audio.cpp source/frontend.cpp source/TextRectangle.cpp source/WindowScreen.cpp source/WindowScreen_Menu.cpp source/devicecapture.cpp source/conversions.cpp source/ExtraButtons.cpp source/Menus/ConnectionMenu.cpp source/Menus/OptionSelectionMenu.cpp source/Menus/MainMenu.cpp source/Menus/VideoMenu.cpp source/Menus/CropMenu.cpp source/Menus/PARMenu.cpp source/Menus/RotationMenu.cpp source/Menus/OffsetMenu.cpp source/Menus/AudioMenu.cpp source/Menus/BFIMenu.cpp source/Menus/RelativePositionMenu.cpp source/Menus/ResolutionMenu.cpp source/Menus/FileConfigMenu.cpp source/Menus/ExtraSettingsMenu.cpp source/Menus/StatusMenu.cpp source/Menus/LicenseMenu.cpp source/WindowCommands.cpp source/Menus/ShortcutMenu.cpp source/Menus/ActionSelectionMenu.cpp source/Menus/ScalingRatioMenu.cpp source/Menus/ISNitroMenu.cpp source/Menus/VideoEffectsMenu.cpp source/CaptureDataBuffers.cpp source/Menus/InputMenu.cpp ${TOOLS_DATA_DIR}/font_ttf.cpp ${TOOLS_DATA_DIR}/shaders_list.cpp ${SOURCE_CPP_EXTRA_FILES})
@@ -498,7 +508,7 @@ endif()
if(USE_FTD2XX_FOR_NEW_DS_LOOPY)
target_link_libraries(${OUTPUT_NAME} PRIVATE ${ftd2xx_BINARY_DIR}/${FTD2XX_SUBFOLDER}/${FTD2XX_LIB})
endif()
target_include_directories(${OUTPUT_NAME} PRIVATE ${EXTRA_INCLUDE_DIRECTORIES} ${TOOLS_DATA_DIR} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/include/Menus ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific/ISDevices ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific/DSCapture_FTD2 ${libftdi1_SOURCE_DIR}/src)
target_include_directories(${OUTPUT_NAME} PRIVATE ${EXTRA_INCLUDE_DIRECTORIES} ${TOOLS_DATA_DIR} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/include/Menus ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific/ISDevices ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific/Nisetro ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific/DSCapture_FTD2 ${libftdi1_SOURCE_DIR}/src)
target_compile_features(${OUTPUT_NAME} PRIVATE cxx_std_20)
target_compile_options(${OUTPUT_NAME} PRIVATE ${EXTRA_CXX_FLAGS})
@@ -537,6 +547,13 @@ add_custom_command(
DEPENDS ${CMAKE_SOURCE_DIR}/bin/ftd2_ds2_fw_2.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION}
)
add_custom_command(
OUTPUT ${TOOLS_DATA_DIR}/nisetro_ds_fw.cpp
COMMENT "Convert fw binary to C - Nisetro DS"
COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/bin/nisetro_ds_fw.bin ${TOOLS_DATA_DIR} nisetro_ds_fw nisetro_ds_fw
DEPENDS ${CMAKE_SOURCE_DIR}/bin/nisetro_ds_fw.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION}
)
set(SHADERS_LIST "")
list(APPEND SHADERS_LIST ${CMAKE_SOURCE_DIR}/shaders/bit_crusher_fragment_shader.2_to_x_1_7.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_crusher_fragment_shader.2_to_x_1_6.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_crusher_fragment_shader_7.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_fragment_shader.2_to_x_0_6.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_fragment_shader_7.frag ${CMAKE_SOURCE_DIR}/shaders/frame_blending_bit_crusher_fragment_shader.2_to_x_1_7.frag ${CMAKE_SOURCE_DIR}/shaders/frame_blending_fragment_shader.frag ${CMAKE_SOURCE_DIR}/shaders/no_effect_fragment_shader.frag)
@@ -606,6 +623,7 @@ else()
install(FILES ${USB_RULES_DIR}/51-istwl.rules DESTINATION .)
install(FILES ${USB_RULES_DIR}/50-ftd2xx.rules DESTINATION .)
install(FILES ${USB_RULES_DIR}/51-ftd2xx.rules DESTINATION .)
install(FILES ${USB_RULES_DIR}/51-nisetro.rules DESTINATION .)
install(FILES ${SETUP_SCRIPTS_DIR}/install_usb_rules${SCRIPT_EXTENSION} DESTINATION .)
endif()

BIN
bin/nisetro_ds_fw.bin Normal file

Binary file not shown.

View File

@@ -0,0 +1,20 @@
#ifndef __CYPRESS_NISETRO_ACQUISITION_HPP
#define __CYPRESS_NISETRO_ACQUISITION_HPP
#include <vector>
#include "utils.hpp"
#include "hw_defs.hpp"
#include "capture_structs.hpp"
#include "display_structs.hpp"
#include "devicecapture.hpp"
void list_devices_cyni_device(std::vector<CaptureDevice> &devices_list, std::vector<no_access_recap_data> &no_access_list);
bool cyni_device_connect_usb(bool print_failed, CaptureData* capture_data, CaptureDevice* device);
uint64_t cyni_device_get_video_in_size(CaptureStatus* status);
uint64_t cyni_device_get_video_in_size(CaptureData* capture_data);
void cyni_device_acquisition_main_loop(CaptureData* capture_data);
void usb_cyni_device_acquisition_cleanup(CaptureData* capture_data);
void usb_cyni_device_init();
void usb_cyni_device_close();
#endif

View File

@@ -0,0 +1,44 @@
#ifndef __CYPRESS_NISETRO_ACQUISITION_GENERAL_HPP
#define __CYPRESS_NISETRO_ACQUISITION_GENERAL_HPP
#include "cypress_nisetro_communications.hpp"
#define NUM_CAPTURE_RECEIVED_DATA_BUFFERS 4
struct CypressDeviceCaptureReceivedData {
volatile bool in_use;
uint32_t index;
CaptureReceived buffer;
SharedConsumerMutex* is_buffer_free_shared_mutex;
size_t* scheduled_special_read;
uint32_t* active_special_read_index;
bool* is_active_special_read;
bool* recalibration_request;
int* status;
uint32_t* last_index;
int* errors_since_last_output;
int* consecutive_output_to_thread;
CaptureData* capture_data;
std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start;
CaptureScreensType curr_capture_type;
cyni_async_callback_data cb_data;
};
std::string get_serial(const cyni_device_usb_device* usb_device_desc, std::string serial, uint16_t bcd_device, int& curr_serial_extra_id);
CaptureDevice cypress_create_device(const cyni_device_usb_device* usb_device_desc, std::string serial, std::string path);
CaptureDevice cypress_create_device(const cyni_device_usb_device* usb_device_desc, std::string serial);
void cypress_insert_device(std::vector<CaptureDevice>& devices_list, const cyni_device_usb_device* usb_device_desc, std::string serial, uint16_t bcd_device, int& curr_serial_extra_id, std::string path);
void cypress_insert_device(std::vector<CaptureDevice>& devices_list, const cyni_device_usb_device* usb_device_desc, std::string serial, uint16_t bcd_device, int& curr_serial_extra_id);
void cypress_output_to_thread(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start, size_t read_size);
int cypress_device_read_frame_and_output(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_start);
int cypress_device_read_frame_request(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, CaptureScreensType curr_capture_type, uint32_t index);
int cypress_device_get_num_free_buffers(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data);
void wait_all_cypress_device_buffers_free(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data);
void wait_one_cypress_device_buffer_free(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data);
bool cypress_device_are_buffers_all_free(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data);
CypressDeviceCaptureReceivedData* cypress_device_get_free_buffer(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data);
int get_cypress_device_status(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data);
void error_cypress_device_status(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, int error_val);
void reset_cypress_device_status(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data);
#endif

View File

@@ -0,0 +1,84 @@
#ifndef __CYPRESS_NISETRO_DEVICE_COMMUNICATIONS_HPP
#define __CYPRESS_NISETRO_DEVICE_COMMUNICATIONS_HPP
#include <libusb.h>
#include <vector>
#include <fstream>
#include <thread>
#include "utils.hpp"
#include "capture_structs.hpp"
enum cypress_nisetro_device_type {
CYPRESS_NISETRO_BLANK_DEVICE,
CYPRESS_NISETRO_DS_DEVICE,
};
typedef void (*cyni_async_callback_function)(void* user_data, int transfer_length, int transfer_status);
struct cyni_async_callback_data {
cyni_async_callback_function function;
void* actual_user_data;
void* transfer_data;
void* handle;
void* extra_transfer_data;
void* base_transfer_data;
std::mutex transfer_data_access;
SharedConsumerMutex* is_transfer_done_mutex;
SharedConsumerMutex* is_transfer_data_ready_mutex;
std::chrono::time_point<std::chrono::high_resolution_clock> start_request;
float timeout_s;
size_t requested_length;
uint8_t* buffer;
size_t actual_length;
int status_value;
int internal_index;
bool is_data_ready;
};
struct cyni_device_usb_device {
std::string name;
std::string long_name;
int vid;
int pid;
int default_config;
int default_interface;
int bulk_timeout;
int ep_ctrl_bulk_in;
int ep_ctrl_bulk_out;
int ep_bulk_in;
cypress_nisetro_device_type device_type;
InputVideoDataType video_data_type;
size_t max_usb_packet_size;
bool do_pipe_clear_reset;
uint8_t* firmware_to_load;
size_t firmware_size;
cypress_nisetro_device_type next_device;
bool has_bcd_device_serial;
int alt_interface;
};
struct cyni_device_device_handlers {
libusb_device_handle* usb_handle;
void* read_handle;
void* write_handle;
void* mutex;
std::string path;
};
int GetNumCyNiDeviceDesc(void);
const cyni_device_usb_device* GetCyNiDeviceDesc(int index);const cyni_device_usb_device* GetNextDeviceDesc(const cyni_device_usb_device* device);
const cyni_device_usb_device* GetNextDeviceDesc(const cyni_device_usb_device* device);
bool has_to_load_firmware(const cyni_device_usb_device* device);
bool load_firmware(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device, uint8_t patch_id);
int capture_start(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device);
int StartCaptureDma(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device);
int capture_end(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device);
int ReadFrame(cyni_device_device_handlers* handlers, uint8_t* buf, int length, const cyni_device_usb_device* device_desc);
int ReadFrameAsync(cyni_device_device_handlers* handlers, uint8_t* buf, int length, const cyni_device_usb_device* device_desc, cyni_async_callback_data* cb_data);
void CloseAsyncRead(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, cyni_async_callback_data* cb_data);
void SetupCypressDeviceAsyncThread(cyni_device_device_handlers* handlers, void* user_data, std::thread* thread_ptr, bool* keep_going, ConsumerMutex* is_data_ready);
void EndCypressDeviceAsyncThread(cyni_device_device_handlers* handlers, void* user_data, std::thread* thread_ptr, bool* keep_going, ConsumerMutex* is_data_ready);
void SetMaxTransferSize(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, size_t new_max_transfer_size);
void pipe_reset_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc);
#endif

View File

@@ -0,0 +1,29 @@
#ifndef __CYPRESS_NISETRO_DRIVER_COMMS_HPP
#define __CYPRESS_NISETRO_DRIVER_COMMS_HPP
#include <vector>
#include "capture_structs.hpp"
#include "utils.hpp"
#include "cypress_nisetro_communications.hpp"
#include "cypress_nisetro_acquisition_general.hpp"
void cypress_driver_list_devices(std::vector<CaptureDevice>& devices_list, bool* not_supported_elems, int* curr_serial_extra_id_cypress, const size_t num_cypress_desc);
void cypress_driver_find_used_serial(const cyni_device_usb_device* usb_device_desc, bool* found, size_t num_free_fw_ids, int &curr_serial_extra_id);
void cypress_nisetro_driver_end_connection(cyni_device_device_handlers* handlers);
int cypress_driver_ctrl_transfer_in(cyni_device_device_handlers* handlers, uint8_t* buffer, size_t inner_size, uint16_t value, uint16_t index, uint16_t request_code, int* num_read);
int cypress_driver_ctrl_transfer_out(cyni_device_device_handlers* handlers, uint8_t* buffer, size_t inner_size, uint16_t value, uint16_t index, uint16_t request_code, int* num_read);
int cypress_driver_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred);
int cypress_driver_ctrl_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred);
int cypress_driver_ctrl_bulk_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred);
void cypress_driver_pipe_reset_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc);
void cypress_driver_pipe_reset_ctrl_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc);
void cypress_driver_pipe_reset_ctrl_bulk_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc);
cyni_device_device_handlers* cypress_driver_serial_reconnection(CaptureDevice* device);
cyni_device_device_handlers* cypress_driver_find_by_serial_number(const cyni_device_usb_device* usb_device_desc, std::string wanted_serial_number, int &curr_serial_extra_id, CaptureDevice* new_device);
int cypress_driver_async_in_start(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, cyni_async_callback_data* cb_data);
void cypress_driver_start_thread(std::thread* thread_ptr, bool* usb_thread_run, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, cyni_device_device_handlers* handlers, ConsumerMutex* AsyncMutexPtr);
void cypress_driver_close_thread(std::thread* thread_ptr, bool* usb_thread_run, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data);
void cypress_driver_cancel_callback(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, cyni_async_callback_data* cb_data);
void cypress_driver_set_transfer_size_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, size_t new_transfer_size);
#endif

View File

@@ -0,0 +1,25 @@
#ifndef __CYPRESS_NISETRO_DEVICE_LIBUSB_HPP
#define __CYPRESS_NISETRO_DEVICE_LIBUSB_HPP
#include <vector>
#include "capture_structs.hpp"
#include "cypress_nisetro_communications.hpp"
void cypress_libusb_start_thread(std::thread* thread_ptr, bool* usb_thread_run);
void cypress_libusb_close_thread(std::thread* thread_ptr, bool* usb_thread_run);
void cypress_libusb_list_devices(std::vector<CaptureDevice> &devices_list, bool* no_access_elems, bool* not_supported_elems, int *curr_serial_extra_id_cypress, const size_t num_cypress_desc);
cyni_device_device_handlers* cypress_libusb_serial_reconnection(const cyni_device_usb_device* usb_device_desc, std::string wanted_serial_number, int &curr_serial_extra_id, CaptureDevice* new_device);
void cypress_libusb_find_used_serial(const cyni_device_usb_device* usb_device_desc, bool* found, size_t num_free_fw_ids, int &curr_serial_extra_id);
void cypress_libusb_end_connection(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device_desc, bool interface_claimed);
int cypress_libusb_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred);
int cypress_libusb_ctrl_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred);
int cypress_libusb_ctrl_bulk_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred);
void cypress_libusb_pipe_reset_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc);
void cypress_libusb_pipe_reset_ctrl_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc);
void cypress_libusb_pipe_reset_ctrl_bulk_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc);
int cypress_libusb_ctrl_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, uint8_t request, uint16_t value, uint16_t index, int* transferred);
int cypress_libusb_ctrl_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, uint8_t request, uint16_t value, uint16_t index, int* transferred);
int cypress_libusb_async_in_start(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, cyni_async_callback_data* cb_data);
void cypress_libusb_cancell_callback(cyni_async_callback_data* cb_data);
#endif

View File

@@ -20,7 +20,7 @@
#define FTD2_INTRA_PACKET_HEADER_SIZE 2
#define MAX_PACKET_SIZE_FTD2 (MAX_PACKET_SIZE_USB2 - FTD2_INTRA_PACKET_HEADER_SIZE)
enum CaptureConnectionType { CAPTURE_CONN_FTD3, CAPTURE_CONN_USB, CAPTURE_CONN_FTD2, CAPTURE_CONN_IS_NITRO };
enum CaptureConnectionType { CAPTURE_CONN_FTD3, CAPTURE_CONN_USB, CAPTURE_CONN_FTD2, CAPTURE_CONN_IS_NITRO, CAPTURE_CONN_CYPRESS_NISETRO };
enum InputVideoDataType { VIDEO_DATA_RGB, VIDEO_DATA_BGR, VIDEO_DATA_RGB16, VIDEO_DATA_BGR16 };
enum CaptureScreensType { CAPTURE_SCREENS_BOTH, CAPTURE_SCREENS_TOP, CAPTURE_SCREENS_BOTTOM, CAPTURE_SCREENS_ENUM_END };
enum CaptureSpeedsType { CAPTURE_SPEEDS_FULL, CAPTURE_SPEEDS_HALF, CAPTURE_SPEEDS_THIRD, CAPTURE_SPEEDS_QUARTER, CAPTURE_SPEEDS_ENUM_END };
@@ -118,6 +118,10 @@ struct ALIGNED(16) PACKED ISNitroCaptureReceived {
ISNitroEmulatorVideoInputData video_in;
};
struct ALIGNED(16) PACKED CypressNisetroDSCaptureReceived {
ISNitroEmulatorVideoInputData video_in;
};
struct ALIGNED(16) PACKED ISTWLCaptureVideoReceived {
ISTWLCaptureVideoInputData video_in;
uint32_t time;
@@ -155,6 +159,7 @@ union CaptureReceived {
FTD2OldDSCaptureReceivedRaw ftd2_received_old_ds_raw;
ISNitroCaptureReceived is_nitro_capture_received;
ISTWLCaptureReceived is_twl_capture_received;
CypressNisetroDSCaptureReceived cypress_nisetro_capture_received;
};
struct CaptureDevice {

View File

@@ -176,12 +176,10 @@ static void STDCALL OverlappedCompletionNothingRoutine(DWORD dwErrorCode, DWORD
}
static void is_driver_close_handle(void** handle, void* default_value = INVALID_HANDLE_VALUE) {
#ifdef _WIN32
if ((*handle) == default_value)
return;
CloseHandle(*handle);
*handle = default_value;
#endif
}
#endif

View File

@@ -0,0 +1,554 @@
#include "devicecapture.hpp"
#include "cypress_nisetro_driver_comms.hpp"
#include "cypress_nisetro_libusb_comms.hpp"
#include "cypress_nisetro_communications.hpp"
#include "cypress_nisetro_acquisition.hpp"
#include "cypress_nisetro_acquisition_general.hpp"
#include "usb_generic.hpp"
#include <libusb.h>
#include <chrono>
#include <cstring>
#define SERIAL_NUMBER_SIZE (0x100 + 1)
#define MAX_TIME_WAIT 1.0
#define MAX_ERRORS_ALLOWED 100
#define NUM_CONSECUTIVE_NEEDED_OUTPUT 6
static void cypress_device_read_frame_cb(void* user_data, int transfer_length, int transfer_status);
static cyni_device_device_handlers* usb_find_by_serial_number(const cyni_device_usb_device* usb_device_desc, std::string wanted_serial_number, CaptureDevice* new_device) {
cyni_device_device_handlers* final_handlers = NULL;
int curr_serial_extra_id = 0;
final_handlers = cypress_libusb_serial_reconnection(usb_device_desc, wanted_serial_number, curr_serial_extra_id, new_device);
if (final_handlers == NULL)
final_handlers = cypress_driver_find_by_serial_number(usb_device_desc, wanted_serial_number, curr_serial_extra_id, new_device);
return final_handlers;
}
static int usb_find_free_fw_id(const cyni_device_usb_device* usb_device_desc) {
int curr_serial_extra_id = 0;
const int num_free_fw_ids = 0x100;
bool found[num_free_fw_ids];
for(int i = 0; i < num_free_fw_ids; i++)
found[i] = false;
cypress_libusb_find_used_serial(usb_device_desc, found, num_free_fw_ids, curr_serial_extra_id);
cypress_driver_find_used_serial(usb_device_desc, found, num_free_fw_ids, curr_serial_extra_id);
for(int i = 0; i < num_free_fw_ids; i++)
if(!found[i])
return i;
return 0;
}
static cyni_device_device_handlers* usb_reconnect(const cyni_device_usb_device* usb_device_desc, CaptureDevice* device) {
cyni_device_device_handlers* final_handlers = NULL;
int curr_serial_extra_id = 0;
final_handlers = cypress_libusb_serial_reconnection(usb_device_desc, device->serial_number, curr_serial_extra_id, NULL);
if (final_handlers == NULL)
final_handlers = cypress_driver_serial_reconnection(device);
return final_handlers;
}
std::string get_serial(const cyni_device_usb_device* usb_device_desc, std::string serial, uint16_t bcd_device, int& curr_serial_extra_id) {
if(serial != "")
return serial;
if(usb_device_desc->has_bcd_device_serial)
return std::to_string(bcd_device & 0xFF);
return std::to_string((curr_serial_extra_id++) + 1);
}
static void cypress_nisetro_connection_end(cyni_device_device_handlers* handlers, const cyni_device_usb_device *device_desc, bool interface_claimed = true) {
if (handlers == NULL)
return;
if (handlers->usb_handle)
cypress_libusb_end_connection(handlers, device_desc, interface_claimed);
else
cypress_nisetro_driver_end_connection(handlers);
delete handlers;
}
CaptureDevice cypress_create_device(const cyni_device_usb_device* usb_device_desc, std::string serial, std::string path) {
return CaptureDevice(serial, usb_device_desc->name, usb_device_desc->long_name, path, CAPTURE_CONN_CYPRESS_NISETRO, (void*)usb_device_desc, false, false, false, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS, usb_device_desc->video_data_type);
}
CaptureDevice cypress_create_device(const cyni_device_usb_device* usb_device_desc, std::string serial) {
return CaptureDevice(serial, usb_device_desc->name, usb_device_desc->long_name, CAPTURE_CONN_CYPRESS_NISETRO, (void*)usb_device_desc, false, false, false, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS, usb_device_desc->video_data_type);;
}
void cypress_insert_device(std::vector<CaptureDevice>& devices_list, const cyni_device_usb_device* usb_device_desc, std::string serial, uint16_t bcd_device, int& curr_serial_extra_id, std::string path) {
devices_list.push_back(cypress_create_device(usb_device_desc, get_serial(usb_device_desc, serial, bcd_device, curr_serial_extra_id), path));
}
void cypress_insert_device(std::vector<CaptureDevice>& devices_list, const cyni_device_usb_device* usb_device_desc, std::string serial, uint16_t bcd_device, int& curr_serial_extra_id) {
devices_list.push_back(cypress_create_device(usb_device_desc, get_serial(usb_device_desc, serial, bcd_device, curr_serial_extra_id)));
}
void list_devices_cyni_device(std::vector<CaptureDevice> &devices_list, std::vector<no_access_recap_data> &no_access_list) {
const size_t num_cyni_device_desc = GetNumCyNiDeviceDesc();
int* curr_serial_extra_id_cyni_device = new int[num_cyni_device_desc];
bool* no_access_elems = new bool[num_cyni_device_desc];
bool* not_supported_elems = new bool[num_cyni_device_desc];
for (int i = 0; i < num_cyni_device_desc; i++) {
no_access_elems[i] = false;
not_supported_elems[i] = false;
curr_serial_extra_id_cyni_device[i] = 0;
}
cypress_libusb_list_devices(devices_list, no_access_elems, not_supported_elems, curr_serial_extra_id_cyni_device, num_cyni_device_desc);
bool any_not_supported = false;
for(int i = 0; i < num_cyni_device_desc; i++)
any_not_supported |= not_supported_elems[i];
for(int i = 0; i < num_cyni_device_desc; i++)
if(no_access_elems[i]) {
const cyni_device_usb_device* usb_device = GetCyNiDeviceDesc(i);
no_access_list.emplace_back(usb_device->vid, usb_device->pid);
}
if(any_not_supported)
cypress_driver_list_devices(devices_list, not_supported_elems, curr_serial_extra_id_cyni_device, num_cyni_device_desc);
delete[] curr_serial_extra_id_cyni_device;
delete[] no_access_elems;
delete[] not_supported_elems;
}
bool cyni_device_connect_usb(bool print_failed, CaptureData* capture_data, CaptureDevice* device) {
const cyni_device_usb_device* usb_device_info = (const cyni_device_usb_device*)device->descriptor;
cyni_device_device_handlers* handlers = usb_reconnect(usb_device_info, device);
if(handlers == NULL) {
capture_error_print(true, capture_data, "Device not found");
return false;
}
if(has_to_load_firmware(usb_device_info)) {
const cyni_device_usb_device* next_usb_device_info = GetNextDeviceDesc(usb_device_info);
int free_fw_id = usb_find_free_fw_id(next_usb_device_info);
int ret = load_firmware(handlers, usb_device_info, free_fw_id);
if(!ret) {
capture_error_print(true, capture_data, "Firmware load error");
return false;
}
cypress_nisetro_connection_end(handlers, usb_device_info);
std::string new_serial_number = std::to_string(free_fw_id);
CaptureDevice new_device;
for(int i = 0; i < 20; i++) {
default_sleep(500);
handlers = usb_find_by_serial_number(next_usb_device_info, new_serial_number, &new_device);
if(handlers != NULL)
break;
}
if(handlers == NULL) {
capture_error_print(true, capture_data, "Device reconnection error");
return false;
}
*device = new_device;
}
capture_data->handle = (void*)handlers;
return true;
}
uint64_t cyni_device_get_video_in_size(cypress_nisetro_device_type device_type) {
return sizeof(CypressNisetroDSCaptureReceived);
}
uint64_t cyni_device_get_video_in_size(CaptureStatus* status) {
return cyni_device_get_video_in_size(((const cyni_device_usb_device*)(status->device.descriptor))->device_type);
}
uint64_t cyni_device_get_video_in_size(CaptureData* capture_data) {
return cyni_device_get_video_in_size(&capture_data->status);
}
static int find_first_vsync_byte(CaptureReceived* capture_buf, size_t read_size) {
uint8_t* data_in = (uint8_t*)capture_buf->cypress_nisetro_capture_received.video_in.screen_data;
if((data_in[0] & 0x80) && (!(data_in[read_size - 1] & 0x80)))
return 0;
int pos = 0;
while((pos < read_size) && (data_in[pos] & 0x80))
pos++;
while((pos < read_size) && (!(data_in[pos] & 0x80)))
pos++;
return pos;
}
void cypress_output_to_thread(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start, size_t read_size, size_t* scheduled_special_read, bool* recalibration_request) {
// Output to the other threads...
int offset = find_first_vsync_byte(capture_buf, read_size);
const cyni_device_usb_device* usb_device_info = (const cyni_device_usb_device*)capture_data->status.device.descriptor;
if(offset) {
if(offset % usb_device_info->max_usb_packet_size)
*recalibration_request = true;
else
*scheduled_special_read = offset;
return;
}
const auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - (*clock_start);
*clock_start = curr_time;
capture_data->data_buffers.WriteToBuffer(capture_buf, read_size, diff.count(), &capture_data->status.device, curr_capture_type);
if (capture_data->status.cooldown_curr_in)
capture_data->status.cooldown_curr_in = capture_data->status.cooldown_curr_in - 1;
capture_data->status.video_wait.unlock();
capture_data->status.audio_wait.unlock();
}
int cypress_device_read_frame_and_output(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_start, size_t* scheduled_special_read, bool* recalibration_request) {
const cyni_device_usb_device* usb_device_info = (const cyni_device_usb_device*)capture_data->status.device.descriptor;
size_t read_size = cyni_device_get_video_in_size(usb_device_info->device_type);
if(*scheduled_special_read)
read_size = *scheduled_special_read;
int ret = ReadFrame((cyni_device_device_handlers*)capture_data->handle, (uint8_t*)capture_buf, read_size, usb_device_info);
if (ret < 0)
return ret;
if(*scheduled_special_read) {
*scheduled_special_read = 0;
return ret;
}
cypress_output_to_thread(capture_data, capture_buf, curr_capture_type, &clock_start, read_size, scheduled_special_read, recalibration_request);
return ret;
}
int cypress_device_read_frame_request(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, CaptureScreensType curr_capture_type, uint32_t index) {
if(cypress_device_capture_recv_data == NULL)
return LIBUSB_SUCCESS;
if((*cypress_device_capture_recv_data->status) < 0) {
cypress_device_capture_recv_data->in_use = false;
return LIBUSB_SUCCESS;
}
const cyni_device_usb_device* usb_device_info = (const cyni_device_usb_device*)capture_data->status.device.descriptor;
cypress_device_capture_recv_data->index = index;
cypress_device_capture_recv_data->curr_capture_type = curr_capture_type;
cypress_device_capture_recv_data->cb_data.function = cypress_device_read_frame_cb;
size_t read_size = cyni_device_get_video_in_size(usb_device_info->device_type);
if(*cypress_device_capture_recv_data->scheduled_special_read) {
read_size = *cypress_device_capture_recv_data->scheduled_special_read;
*cypress_device_capture_recv_data->active_special_read_index = index;
*cypress_device_capture_recv_data->is_active_special_read = true;
*cypress_device_capture_recv_data->scheduled_special_read = 0;
}
return ReadFrameAsync((cyni_device_device_handlers*)capture_data->handle, (uint8_t*)&cypress_device_capture_recv_data->buffer, read_size, usb_device_info, &cypress_device_capture_recv_data->cb_data);
}
static void end_cypress_device_read_frame_cb(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) {
cypress_device_capture_recv_data->in_use = false;
cypress_device_capture_recv_data->is_buffer_free_shared_mutex->specific_unlock(cypress_device_capture_recv_data->cb_data.internal_index);
}
static void cypress_device_read_frame_cb(void* user_data, int transfer_length, int transfer_status) {
CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data = (CypressDeviceCaptureReceivedData*)user_data;
if((*cypress_device_capture_recv_data->status) < 0)
return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data);
if(transfer_status != LIBUSB_TRANSFER_COMPLETED) {
int error = LIBUSB_ERROR_OTHER;
if(transfer_status == LIBUSB_TRANSFER_TIMED_OUT)
error = LIBUSB_ERROR_TIMEOUT;
else {
*cypress_device_capture_recv_data->errors_since_last_output += 1;
*cypress_device_capture_recv_data->consecutive_output_to_thread = 0;
}
*cypress_device_capture_recv_data->status = error;
return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data);
}
if(((int32_t)(cypress_device_capture_recv_data->index - (*cypress_device_capture_recv_data->last_index))) <= 0) {
//*cypress_device_capture_recv_data->status = LIBUSB_ERROR_INTERRUPTED;
return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data);
}
*cypress_device_capture_recv_data->consecutive_output_to_thread += 1;
if((*cypress_device_capture_recv_data->consecutive_output_to_thread) > NUM_CONSECUTIVE_NEEDED_OUTPUT)
*cypress_device_capture_recv_data->errors_since_last_output = 0;
*cypress_device_capture_recv_data->last_index = cypress_device_capture_recv_data->index;
if((*cypress_device_capture_recv_data->is_active_special_read) && (((int32_t)(cypress_device_capture_recv_data->index - (*cypress_device_capture_recv_data->active_special_read_index))) >= 0)) {
*cypress_device_capture_recv_data->is_active_special_read = false;
return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data);
}
if((*cypress_device_capture_recv_data->scheduled_special_read) || (*cypress_device_capture_recv_data->is_active_special_read) || (*cypress_device_capture_recv_data->recalibration_request))
return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data);
cypress_output_to_thread(cypress_device_capture_recv_data->capture_data, &cypress_device_capture_recv_data->buffer, cypress_device_capture_recv_data->curr_capture_type, cypress_device_capture_recv_data->clock_start, transfer_length, cypress_device_capture_recv_data->scheduled_special_read, cypress_device_capture_recv_data->recalibration_request);
end_cypress_device_read_frame_cb(cypress_device_capture_recv_data);
}
int cypress_device_get_num_free_buffers(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) {
int num_free = 0;
for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++)
if(!cypress_device_capture_recv_data[i].in_use)
num_free += 1;
return num_free;
}
static void close_all_reads_error(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, bool &async_read_closed) {
cyni_device_device_handlers* handlers = (cyni_device_device_handlers*)capture_data->handle;
const cyni_device_usb_device* usb_device_desc = (const cyni_device_usb_device*)capture_data->status.device.descriptor;
if(get_cypress_device_status(cypress_device_capture_recv_data) < 0) {
if(!async_read_closed) {
if(handlers->usb_handle) {
for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++)
CloseAsyncRead(handlers, usb_device_desc, &cypress_device_capture_recv_data[i].cb_data);
}
else
CloseAsyncRead(handlers, usb_device_desc, &cypress_device_capture_recv_data[0].cb_data);
async_read_closed = true;
}
}
}
static bool has_too_much_time_passed(const std::chrono::time_point<std::chrono::high_resolution_clock> &start_time) {
const auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - start_time;
return diff.count() > MAX_TIME_WAIT;
}
static void error_too_much_time_passed(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, bool &async_read_closed, const std::chrono::time_point<std::chrono::high_resolution_clock> &start_time) {
if(has_too_much_time_passed(start_time)) {
error_cypress_device_status(cypress_device_capture_recv_data, -1);
close_all_reads_error(capture_data, cypress_device_capture_recv_data, async_read_closed);
}
}
void wait_all_cypress_device_buffers_free(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) {
if(cypress_device_capture_recv_data == NULL)
return;
cyni_device_device_handlers* handlers = (cyni_device_device_handlers*)capture_data->handle;
bool async_read_closed = false;
close_all_reads_error(capture_data, cypress_device_capture_recv_data, async_read_closed);
const auto start_time = std::chrono::high_resolution_clock::now();
for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++)
while(cypress_device_capture_recv_data[i].in_use) {
error_too_much_time_passed(capture_data, cypress_device_capture_recv_data, async_read_closed, start_time);
cypress_device_capture_recv_data[i].is_buffer_free_shared_mutex->specific_timed_lock(i);
}
}
void wait_one_cypress_device_buffer_free(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) {
cyni_device_device_handlers* handlers = (cyni_device_device_handlers*)capture_data->handle;
bool done = false;
const auto start_time = std::chrono::high_resolution_clock::now();
while(!done) {
for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) {
if(!cypress_device_capture_recv_data[i].in_use)
done = true;
}
if(!done) {
if(has_too_much_time_passed(start_time))
return;
if(get_cypress_device_status(cypress_device_capture_recv_data) < 0)
return;
int dummy = 0;
cypress_device_capture_recv_data[0].is_buffer_free_shared_mutex->general_timed_lock(&dummy);
}
}
}
void wait_specific_cypress_device_buffer_free(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) {
cyni_device_device_handlers* handlers = (cyni_device_device_handlers*)capture_data->handle;
bool done = false;
const auto start_time = std::chrono::high_resolution_clock::now();
while(!done) {
if(!cypress_device_capture_recv_data->in_use)
done = true;
if(!done) {
if(has_too_much_time_passed(start_time))
return;
if(get_cypress_device_status(cypress_device_capture_recv_data) < 0)
return;
int dummy = 0;
cypress_device_capture_recv_data->is_buffer_free_shared_mutex->general_timed_lock(&dummy);
}
}
}
bool cypress_device_are_buffers_all_free(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) {
return cypress_device_get_num_free_buffers(cypress_device_capture_recv_data) == NUM_CAPTURE_RECEIVED_DATA_BUFFERS;
}
CypressDeviceCaptureReceivedData* cypress_device_get_free_buffer(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) {
wait_one_cypress_device_buffer_free(capture_data, cypress_device_capture_recv_data);
if(get_cypress_device_status(cypress_device_capture_recv_data) < 0)
return NULL;
for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++)
if(!cypress_device_capture_recv_data[i].in_use) {
cypress_device_capture_recv_data[i].is_buffer_free_shared_mutex->specific_try_lock(i);
cypress_device_capture_recv_data[i].in_use = true;
return &cypress_device_capture_recv_data[i];
}
return NULL;
}
int get_cypress_device_status(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) {
return *cypress_device_capture_recv_data[0].status;
}
void error_cypress_device_status(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, int error_val) {
if((error_val == 0) || (get_cypress_device_status(cypress_device_capture_recv_data) == 0))
*cypress_device_capture_recv_data[0].status = error_val;
}
void reset_cypress_device_status(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) {
error_cypress_device_status(cypress_device_capture_recv_data, 0);
}
void recalibration_reads(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, CypressDeviceCaptureReceivedData* chosen_buffer, uint32_t &index, CaptureScreensType curr_capture_type) {
CaptureData* capture_data = cypress_device_capture_recv_data[0].capture_data;
do {
if(get_cypress_device_status(cypress_device_capture_recv_data) < 0)
return;
chosen_buffer->in_use = false;
wait_all_cypress_device_buffers_free(capture_data, cypress_device_capture_recv_data);
chosen_buffer->in_use = true;
if(get_cypress_device_status(cypress_device_capture_recv_data) < 0)
return;
CypressDeviceCaptureReceivedData* next_buffer = cypress_device_get_free_buffer(capture_data, cypress_device_capture_recv_data);
default_sleep();
*chosen_buffer->recalibration_request = false;
chosen_buffer->in_use = true;
int ret = cypress_device_read_frame_request(capture_data, chosen_buffer, curr_capture_type, index++);
if(ret < 0) {
error_cypress_device_status(cypress_device_capture_recv_data, ret);
return;
}
ret = cypress_device_read_frame_request(capture_data, next_buffer, curr_capture_type, index++);
if(ret < 0) {
next_buffer->in_use = false;
error_cypress_device_status(cypress_device_capture_recv_data, ret);
wait_specific_cypress_device_buffer_free(capture_data, chosen_buffer);
chosen_buffer->in_use = true;
return;
}
wait_specific_cypress_device_buffer_free(capture_data, chosen_buffer);
} while((*chosen_buffer->recalibration_request) && capture_data->status.connected && capture_data->status.running);
chosen_buffer->in_use = true;
}
static bool cyni_device_acquisition_loop(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) {
cyni_device_device_handlers* handlers = (cyni_device_device_handlers*)capture_data->handle;
const cyni_device_usb_device* usb_device_desc = (const cyni_device_usb_device*)capture_data->status.device.descriptor;
uint32_t index = 0;
CaptureScreensType curr_capture_type = capture_data->status.capture_type;
CaptureSpeedsType curr_capture_speed = capture_data->status.capture_speed;
int ret = capture_start(handlers, usb_device_desc);
if (ret < 0) {
capture_error_print(true, capture_data, "Capture Start: Failed");
return false;
}
SetMaxTransferSize(handlers, usb_device_desc, cyni_device_get_video_in_size(usb_device_desc->device_type));
auto clock_last_reset = std::chrono::high_resolution_clock::now();
for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) {
CypressDeviceCaptureReceivedData* chosen_buffer = cypress_device_get_free_buffer(capture_data, cypress_device_capture_recv_data);
ret = cypress_device_read_frame_request(capture_data, chosen_buffer, curr_capture_type, index++);
if(ret < 0) {
chosen_buffer->in_use = false;
error_cypress_device_status(cypress_device_capture_recv_data, ret);
capture_error_print(true, capture_data, "Initial Reads: Failed");
return false;
}
}
StartCaptureDma(handlers, usb_device_desc);
while (capture_data->status.connected && capture_data->status.running) {
ret = get_cypress_device_status(cypress_device_capture_recv_data);
if(ret < 0) {
wait_all_cypress_device_buffers_free(capture_data, cypress_device_capture_recv_data);
if((*cypress_device_capture_recv_data[0].errors_since_last_output) > MAX_ERRORS_ALLOWED) {
capture_error_print(true, capture_data, "Disconnected: Read error");
return false;
}
*cypress_device_capture_recv_data[0].recalibration_request = false;
*cypress_device_capture_recv_data[0].scheduled_special_read = 0;
*cypress_device_capture_recv_data[0].is_active_special_read = false;
pipe_reset_bulk_in(handlers, usb_device_desc);
reset_cypress_device_status(cypress_device_capture_recv_data);
default_sleep(100);
}
CypressDeviceCaptureReceivedData* chosen_buffer = cypress_device_get_free_buffer(capture_data, cypress_device_capture_recv_data);
if(chosen_buffer == NULL)
error_cypress_device_status(cypress_device_capture_recv_data, LIBUSB_ERROR_TIMEOUT);
if(chosen_buffer && (*chosen_buffer->recalibration_request)) {
*chosen_buffer->recalibration_request = false;
recalibration_reads(handlers, usb_device_desc, cypress_device_capture_recv_data, chosen_buffer, index, curr_capture_type);
}
ret = cypress_device_read_frame_request(capture_data, chosen_buffer, curr_capture_type, index++);
if(ret < 0) {
chosen_buffer->in_use = false;
error_cypress_device_status(cypress_device_capture_recv_data, ret);
capture_error_print(true, capture_data, "Setup Read: Failed");
return false;
}
}
return true;
}
void cyni_device_acquisition_main_loop(CaptureData* capture_data) {
if(!usb_is_initialized())
return;
bool is_done_thread;
ConsumerMutex has_data_been_processed;
std::thread async_processing_thread;
cyni_device_device_handlers* handlers = (cyni_device_device_handlers*)capture_data->handle;
const cyni_device_usb_device* usb_device_desc = (const cyni_device_usb_device*)capture_data->status.device.descriptor;
uint32_t last_index = -1;
int status = 0;
cyni_async_callback_data* cb_queue[NUM_CAPTURE_RECEIVED_DATA_BUFFERS];
int queue_elems = 0;
size_t scheduled_special_read = 0;
uint32_t active_special_read_index = 0;
bool is_active_special_read = false;
bool one_transfer_active = false;
bool recalibration_request = false;
int errors_since_last_output = 0;
int consecutive_output_to_thread = 0;
SharedConsumerMutex is_buffer_free_shared_mutex(NUM_CAPTURE_RECEIVED_DATA_BUFFERS);
SharedConsumerMutex is_transfer_done_shared_mutex(NUM_CAPTURE_RECEIVED_DATA_BUFFERS);
SharedConsumerMutex is_transfer_data_ready_shared_mutex(NUM_CAPTURE_RECEIVED_DATA_BUFFERS);
std::chrono::time_point<std::chrono::high_resolution_clock> clock_start = std::chrono::high_resolution_clock::now();
CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data = new CypressDeviceCaptureReceivedData[NUM_CAPTURE_RECEIVED_DATA_BUFFERS];
for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) {
cypress_device_capture_recv_data[i].in_use = false;
cypress_device_capture_recv_data[i].index = i;
cypress_device_capture_recv_data[i].capture_data = capture_data;
cypress_device_capture_recv_data[i].scheduled_special_read = &scheduled_special_read;
cypress_device_capture_recv_data[i].active_special_read_index = &active_special_read_index;
cypress_device_capture_recv_data[i].is_active_special_read = &is_active_special_read;
cypress_device_capture_recv_data[i].last_index = &last_index;
cypress_device_capture_recv_data[i].errors_since_last_output = &errors_since_last_output;
cypress_device_capture_recv_data[i].recalibration_request = &recalibration_request;
cypress_device_capture_recv_data[i].consecutive_output_to_thread = &consecutive_output_to_thread;
cypress_device_capture_recv_data[i].clock_start = &clock_start;
cypress_device_capture_recv_data[i].is_buffer_free_shared_mutex = &is_buffer_free_shared_mutex;
cypress_device_capture_recv_data[i].status = &status;
cypress_device_capture_recv_data[i].cb_data.actual_user_data = &cypress_device_capture_recv_data[i];
cypress_device_capture_recv_data[i].cb_data.transfer_data = NULL;
cypress_device_capture_recv_data[i].cb_data.is_transfer_done_mutex = &is_transfer_done_shared_mutex;
cypress_device_capture_recv_data[i].cb_data.internal_index = i;
cypress_device_capture_recv_data[i].cb_data.is_transfer_data_ready_mutex = &is_transfer_data_ready_shared_mutex;
}
SetupCypressDeviceAsyncThread(handlers, cypress_device_capture_recv_data, &async_processing_thread, &is_done_thread, &has_data_been_processed);
bool proper_return = cyni_device_acquisition_loop(capture_data, cypress_device_capture_recv_data);
wait_all_cypress_device_buffers_free(capture_data, cypress_device_capture_recv_data);
EndCypressDeviceAsyncThread(handlers, cypress_device_capture_recv_data, &async_processing_thread, &is_done_thread, &has_data_been_processed);
delete []cypress_device_capture_recv_data;
if(proper_return)
capture_end(handlers, usb_device_desc);
}
void usb_cyni_device_acquisition_cleanup(CaptureData* capture_data) {
if(!usb_is_initialized())
return;
cypress_nisetro_connection_end((cyni_device_device_handlers*)capture_data->handle, (const cyni_device_usb_device*)capture_data->status.device.descriptor);
capture_data->handle = NULL;
}
void usb_cyni_device_init() {
return usb_init();
}
void usb_cyni_device_close() {
usb_close();
}

View File

@@ -0,0 +1,256 @@
#include "frontend.hpp"
#include "cypress_nisetro_communications.hpp"
#include "cypress_nisetro_libusb_comms.hpp"
#include "cypress_nisetro_driver_comms.hpp"
#include "cypress_nisetro_acquisition_general.hpp"
#include "nisetro_ds_fw.h"
#include <libusb.h>
#include <cstring>
#include <thread>
#include <chrono>
#include <iostream>
#define CYPRESS_BASE_USB_PACKET_LIMIT 64
#define CYPRESS_NISETRO_USB_PACKET_LIMIT 512
#define CMD_EP6IN_START 0x50
#define CMD_EP6IN_STOP 0x51
#define CMD_EP2OUT_START 0x52
#define CMD_EP2OUT_STOP 0x53
#define CMD_PORT_CFG 0x54
#define CMD_REG_READ 0x55
#define CMD_REG_WRITE 0x56
#define CMD_PORT_READ 0x57
#define CMD_PORT_WRITE 0x58
#define CMD_IFCONFIG 0x59
#define CMD_MODE_IDLE 0x5a
#define PIO_DROP 0x20
#define PIO_RESET 0x10
#define PIO_DIR 0x08
static const cyni_device_usb_device cypress_fx2_generic_device = {
.name = "EZ-USB FX2", .long_name = "EZ-USB FX2",
.vid = 0x04B4, .pid = 0x8613,
.default_config = 1, .default_interface = 0,
.bulk_timeout = 500,
.ep_ctrl_bulk_in = 0, .ep_ctrl_bulk_out = 0,
.ep_bulk_in = 0,
.device_type = CYPRESS_NISETRO_BLANK_DEVICE,
.video_data_type = VIDEO_DATA_RGB, .max_usb_packet_size = CYPRESS_BASE_USB_PACKET_LIMIT,
.do_pipe_clear_reset = false,
.firmware_to_load = nisetro_ds_fw, .firmware_size = nisetro_ds_fw_len,
.next_device = CYPRESS_NISETRO_DS_DEVICE,
.has_bcd_device_serial = false, .alt_interface = 1
};
static const cyni_device_usb_device cypress_fx2_nisetro_ds_device = {
.name = "Nisetro DS", .long_name = "Nisetro DS",
.vid = 0x04B4, .pid = 0x1004,
.default_config = 1, .default_interface = 0,
.bulk_timeout = 500,
.ep_ctrl_bulk_in = 1 | LIBUSB_ENDPOINT_IN, .ep_ctrl_bulk_out = 1 | LIBUSB_ENDPOINT_OUT,
.ep_bulk_in = 6 | LIBUSB_ENDPOINT_IN,
.device_type = CYPRESS_NISETRO_DS_DEVICE,
.video_data_type = VIDEO_DATA_RGB, .max_usb_packet_size = CYPRESS_NISETRO_USB_PACKET_LIMIT,
.do_pipe_clear_reset = true,
.firmware_to_load = NULL, .firmware_size = 0,
.next_device = CYPRESS_NISETRO_DS_DEVICE,
.has_bcd_device_serial = true, .alt_interface = 0
};
static const cyni_device_usb_device* all_usb_cyni_device_devices_desc[] = {
&cypress_fx2_generic_device,
&cypress_fx2_nisetro_ds_device,
};
static int ctrl_in_transfer(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, uint8_t request, uint16_t value, uint16_t index, int* transferred) {
if(handlers->usb_handle)
return cypress_libusb_ctrl_in(handlers, usb_device_desc, buf, length, request, value, index, transferred);
return cypress_driver_ctrl_transfer_in(handlers, buf, length, value, index, request, transferred);
}
static int ctrl_out_transfer(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, uint8_t request, uint16_t value, uint16_t index, int* transferred) {
if(handlers->usb_handle)
return cypress_libusb_ctrl_out(handlers, usb_device_desc, buf, length, request, value, index, transferred);
return cypress_driver_ctrl_transfer_out(handlers, buf, length, value, index, request, transferred);
}
static int bulk_in_transfer(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) {
if(handlers->usb_handle)
return cypress_libusb_bulk_in(handlers, usb_device_desc, buf, length, transferred);
return cypress_driver_bulk_in(handlers, usb_device_desc, buf, length, transferred);
}
static int bulk_in_async(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t *buf, int length, cyni_async_callback_data* cb_data) {
if(handlers->usb_handle)
return cypress_libusb_async_in_start(handlers, usb_device_desc, buf, length, cb_data);
return cypress_driver_async_in_start(handlers, usb_device_desc, buf, length, cb_data);
}
static int ctrl_bulk_in_transfer(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) {
if(handlers->usb_handle)
return cypress_libusb_ctrl_bulk_in(handlers, usb_device_desc, buf, length, transferred);
return cypress_driver_ctrl_bulk_in(handlers, usb_device_desc, buf, length, transferred);
}
static int ctrl_bulk_out_transfer(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) {
if(handlers->usb_handle)
return cypress_libusb_ctrl_bulk_out(handlers, usb_device_desc, buf, length, transferred);
return cypress_driver_ctrl_bulk_out(handlers, usb_device_desc, buf, length, transferred);
}
void pipe_reset_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc) {
if(handlers->usb_handle)
return cypress_libusb_pipe_reset_bulk_in(handlers, usb_device_desc);
return cypress_driver_pipe_reset_bulk_in(handlers, usb_device_desc);
}
static void pipe_reset_ctrl_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc) {
if(handlers->usb_handle)
return cypress_libusb_pipe_reset_ctrl_bulk_in(handlers, usb_device_desc);
return cypress_driver_pipe_reset_ctrl_bulk_in(handlers, usb_device_desc);
}
static void pipe_reset_ctrl_bulk_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc) {
if(handlers->usb_handle)
return cypress_libusb_pipe_reset_ctrl_bulk_out(handlers, usb_device_desc);
return cypress_driver_pipe_reset_ctrl_bulk_out(handlers, usb_device_desc);
}
int GetNumCyNiDeviceDesc() {
return sizeof(all_usb_cyni_device_devices_desc) / sizeof(all_usb_cyni_device_devices_desc[0]);
}
const cyni_device_usb_device* GetCyNiDeviceDesc(int index) {
if((index < 0) || (index >= GetNumCyNiDeviceDesc()))
index = 0;
return all_usb_cyni_device_devices_desc[index];
}
const cyni_device_usb_device* GetNextDeviceDesc(const cyni_device_usb_device* device) {
for(int i = 0; i < GetNumCyNiDeviceDesc(); i++) {
const cyni_device_usb_device* examined_device = GetCyNiDeviceDesc(i);
if(examined_device->device_type == device->next_device)
return examined_device;
}
return NULL;
}
bool has_to_load_firmware(const cyni_device_usb_device* device) {
return !((device->firmware_to_load == NULL) || (device->firmware_size == 0));
}
bool load_firmware(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device, uint8_t patch_id) {
if(!has_to_load_firmware(device))
return true;
int transferred = 0;
uint8_t* fw_data = new uint8_t[device->firmware_size];
memcpy(fw_data, device->firmware_to_load, device->firmware_size);
int num_patches = read_le16(fw_data, 1);
for(int i = 0; i < num_patches; i++) {
int pos_patch = read_le16(fw_data, 2 + i);
write_le16(fw_data + pos_patch, patch_id | 0xFF00);
}
uint8_t buffer[0x8000];
buffer[0] = 1;
int ret = ctrl_out_transfer(handlers, device, buffer, 1, 0xA0, 0xE600, 0, &transferred);
if(ret < 0) {
delete []fw_data;
return false;
}
bool done = false;
int fw_pos = read_le16(fw_data);
while(!done) {
int inside_len = read_be16(fw_data + fw_pos);
int offset = read_be16(fw_data + fw_pos, 1);
done = (inside_len & 0x8000) != 0;
inside_len &= 0x7FFF;
fw_pos += 4;
if((inside_len + fw_pos) > device->firmware_size) {
delete []fw_data;
return false;
}
memcpy(buffer, fw_data + fw_pos, inside_len);
fw_pos += inside_len;
ret = ctrl_out_transfer(handlers, device, buffer, inside_len, 0xA0, offset, 0, &transferred);
if(ret < 0) {
delete []fw_data;
return false;
}
}
delete []fw_data;
return true;
}
int capture_start(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device) {
uint8_t buffer[] = { CMD_PORT_CFG, 0x07, PIO_RESET | PIO_DIR, CMD_MODE_IDLE, CMD_IFCONFIG, 0xE3, CMD_REG_WRITE, 0, 0x08, CMD_MODE_IDLE};
int transferred = 0;
pipe_reset_ctrl_bulk_in(handlers, device);
pipe_reset_ctrl_bulk_out(handlers, device);
int ret = ctrl_bulk_out_transfer(handlers, device, buffer, sizeof(buffer), &transferred);
if(ret < 0)
return ret;
pipe_reset_bulk_in(handlers, device);
return ret;
}
int StartCaptureDma(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device) {
uint8_t buffer[] = { CMD_PORT_WRITE, PIO_RESET, CMD_EP6IN_START, CMD_PORT_WRITE, 0};
int transferred = 0;
return ctrl_bulk_out_transfer(handlers, device, buffer, sizeof(buffer), &transferred);
}
int capture_end(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device) {
int transferred = 0;
uint8_t buffer[] = { CMD_PORT_WRITE, 0, CMD_EP6IN_STOP, CMD_MODE_IDLE};
int ret = ctrl_bulk_out_transfer(handlers, device, buffer, sizeof(buffer), &transferred);
if(ret < 0)
return ret;
uint8_t buffer2[] = { CMD_REG_READ, 0, CMD_REG_READ, 1, CMD_REG_READ, 2, CMD_REG_READ, 3, CMD_REG_READ, 4, CMD_REG_READ, 5, CMD_REG_READ, 6, CMD_REG_READ, 7};
ret = ctrl_bulk_out_transfer(handlers, device, buffer2, sizeof(buffer2), &transferred);
if(ret < 0)
return ret;
pipe_reset_ctrl_bulk_in(handlers, device);
return ctrl_bulk_in_transfer(handlers, device, buffer2, 8, &transferred);
}
void SetMaxTransferSize(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, size_t new_max_transfer_size) {
if(handlers->usb_handle)
return;
cypress_driver_set_transfer_size_bulk_in(handlers, usb_device_desc, new_max_transfer_size);
}
int ReadFrame(cyni_device_device_handlers* handlers, uint8_t* buf, int length, const cyni_device_usb_device* device_desc) {
// Maybe making this async would be better for lower end hardware...
int num_bytes = 0;
int ret = bulk_in_transfer(handlers, device_desc, buf, length, &num_bytes);
if(num_bytes != length)
return LIBUSB_ERROR_INTERRUPTED;
return ret;
}
int ReadFrameAsync(cyni_device_device_handlers* handlers, uint8_t* buf, int length, const cyni_device_usb_device* device_desc, cyni_async_callback_data* cb_data) {
return bulk_in_async(handlers, device_desc, buf, length, cb_data);
}
void CloseAsyncRead(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, cyni_async_callback_data* cb_data) {
if(handlers->usb_handle)
return cypress_libusb_cancell_callback(cb_data);
return cypress_driver_cancel_callback(handlers, usb_device_desc, cb_data);
}
void SetupCypressDeviceAsyncThread(cyni_device_device_handlers* handlers, void* user_data, std::thread* thread_ptr, bool* keep_going, ConsumerMutex* is_data_ready) {
if(handlers->usb_handle)
return cypress_libusb_start_thread(thread_ptr, keep_going);
return cypress_driver_start_thread(thread_ptr, keep_going, (CypressDeviceCaptureReceivedData*)user_data, handlers, is_data_ready);
}
void EndCypressDeviceAsyncThread(cyni_device_device_handlers* handlers, void* user_data, std::thread* thread_ptr, bool* keep_going, ConsumerMutex* is_data_ready) {
if(handlers->usb_handle)
return cypress_libusb_close_thread(thread_ptr, keep_going);
return cypress_driver_close_thread(thread_ptr, keep_going, (CypressDeviceCaptureReceivedData*)user_data);
}

View File

@@ -0,0 +1,716 @@
#include "cypress_nisetro_driver_comms.hpp"
#include "cypress_nisetro_acquisition_general.hpp"
#include <algorithm>
#include <filesystem>
#ifdef _WIN32
#include <setupapi.h>
#include <devioctl.h>
#define BASE_IOCTL_INDEX 0
#define DIR_HOST_TO_DEVICE 0
#define DIR_DEVICE_TO_HOST 1
#define IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER CTL_CODE(FILE_DEVICE_UNKNOWN, BASE_IOCTL_INDEX + 8, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_ADAPT_SEND_NON_EP0_DIRECT CTL_CODE(FILE_DEVICE_UNKNOWN, BASE_IOCTL_INDEX + 18, METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_ADAPT_RESET_PIPE CTL_CODE(FILE_DEVICE_UNKNOWN, BASE_IOCTL_INDEX + 11, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_ADAPT_SET_TRANSFER_SIZE CTL_CODE(FILE_DEVICE_UNKNOWN, BASE_IOCTL_INDEX + 14, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_ADAPT_ABORT_PIPE CTL_CODE(FILE_DEVICE_UNKNOWN, BASE_IOCTL_INDEX + 17, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define USB_REQUEST_GET_STATUS 0x00
#define USB_REQUEST_CLEAR_FEATURE 0x01
#define USB_REQUEST_SET_FEATURE 0x03
#define USB_REQUEST_SET_ADDRESS 0x05
#define USB_REQUEST_GET_DESCRIPTOR 0x06
#define USB_REQUEST_SET_DESCRIPTOR 0x07
#define USB_REQUEST_GET_CONFIGURATION 0x08
#define USB_REQUEST_SET_CONFIGURATION 0x09
#define USB_REQUEST_GET_INTERFACE 0x0A
#define USB_REQUEST_SET_INTERFACE 0x0B
#define USB_REQUEST_SYNC_FRAME 0x0C
#define USB_DEVICE_DESCRIPTOR_TYPE 0x01
#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02
#define USB_STRING_DESCRIPTOR_TYPE 0x03
#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04
#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05
#define TARGET_DEVICE 0
#define REQUEST_STANDARD 0
#define REQUEST_VENDOR 2
#pragma pack(push, 1)
struct PACKED USB_COMMON_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
};
struct PACKED USB_STRING_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
WCHAR bString[1];
};
struct PACKED USB_DEVICE_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
USHORT bcdUSB;
UCHAR bDeviceClass;
UCHAR bDeviceSubClass;
UCHAR bDeviceProtocol;
UCHAR bMaxPacketSize0;
USHORT idVendor;
USHORT idProduct;
USHORT bcdDevice;
UCHAR iManufacturer;
UCHAR iProduct;
UCHAR iSerialNumber;
UCHAR bNumConfigurations;
};
// Is this fine? Without any check for endianness?
// Shouldn't all of this be packed?!
struct PACKED CYPRESS_WORD_SPLIT {
UCHAR lowByte;
UCHAR hiByte;
};
struct PACKED CYPRESS_BM_REQ_TYPE {
UCHAR Recipient:2;
UCHAR Reserved:3;
UCHAR Type:2;
UCHAR Direction:1;
};
struct PACKED CYPRESS_SETUP_PACKET {
union {
CYPRESS_BM_REQ_TYPE bmReqType;
UCHAR bmRequest;
};
UCHAR bRequest;
union {
CYPRESS_WORD_SPLIT wVal;
USHORT wValue;
};
union {
CYPRESS_WORD_SPLIT wIndx;
USHORT wIndex;
};
union {
CYPRESS_WORD_SPLIT wLen;
USHORT wLength;
};
ULONG ulTimeOut;
};
struct PACKED CYPRESS_ISO_ADV_PARAMS {
USHORT isoId;
USHORT isoCmd;
ULONG ulParam1;
ULONG ulParam2;
};
struct PACKED CYPRESS_SINGLE_TRANSFER {
union {
CYPRESS_SETUP_PACKET SetupPacket;
CYPRESS_ISO_ADV_PARAMS IsoParams;
};
UCHAR reserved;
UCHAR ucEndpointAddress;
ULONG NtStatus;
ULONG UsbdStatus;
ULONG IsoPacketOffset;
ULONG IsoPacketLength;
ULONG BufferOffset;
ULONG BufferLength;
};
struct PACKED CYPRESS_SET_TRANSFER_SIZE_INFO {
UCHAR EndpointAddress;
ULONG TransferSize;
};
#pragma pack(pop)
static GUID cypress_driver_guid = {.Data1 = 0xae18aa60, .Data2 = 0x7f6a, .Data3 = 0x11d4, .Data4 = {0x97, 0xdd, 0x0, 0x1, 0x2, 0x29, 0xb9, 0x59}};
static void cypress_driver_wait_async_transfers(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) {
HANDLE to_wait_array[NUM_CAPTURE_RECEIVED_DATA_BUFFERS];
for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++)
to_wait_array[i] = ((OVERLAPPED*)cypress_device_capture_recv_data[i].cb_data.base_transfer_data)->hEvent;
WaitForMultipleObjects(NUM_CAPTURE_RECEIVED_DATA_BUFFERS, to_wait_array, false, 300);
}
static bool cypress_driver_process_async_transfers(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, cyni_device_device_handlers* handlers) {
bool found = false;
for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) {
cyni_async_callback_data* cb_data = (cyni_async_callback_data*)&cypress_device_capture_recv_data[i].cb_data;
bool possible_result = false;
bool is_data_ready = false;
cb_data->transfer_data_access.lock();
possible_result = cb_data->transfer_data != NULL;
is_data_ready = cb_data->is_data_ready;
cb_data->transfer_data_access.unlock();
if(cypress_device_capture_recv_data[i].in_use && is_data_ready)
found = true;
if(cypress_device_capture_recv_data[i].in_use && possible_result) {
DWORD bytes_transferred = 0;
int error = 0;
if(!GetOverlappedResult(handlers->read_handle, (OVERLAPPED*)cb_data->transfer_data, &bytes_transferred, false))
error = GetLastError();
if(error == ERROR_IO_INCOMPLETE) {
const auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - cb_data->start_request;
if(diff.count() > cb_data->timeout_s)
error_cypress_device_status(cypress_device_capture_recv_data, LIBUSB_ERROR_TIMEOUT);
}
if(error != ERROR_IO_INCOMPLETE) {
CYPRESS_SINGLE_TRANSFER* transfer_info = (CYPRESS_SINGLE_TRANSFER*)cb_data->extra_transfer_data;
if(!error) {
error = transfer_info->UsbdStatus;
if(!error)
error = transfer_info->NtStatus;
}
cb_data->actual_length = bytes_transferred;
cb_data->status_value = error;
cb_data->transfer_data = NULL;
cb_data->is_data_ready = true;
found = true;
}
}
}
return found;
}
static void cypress_driver_function(bool* usb_thread_run, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, cyni_device_device_handlers* handlers) {
int ret = 0;
while(*usb_thread_run) {
if(cypress_driver_process_async_transfers(cypress_device_capture_recv_data, handlers)) {
for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) {
cyni_async_callback_data* cb_data = (cyni_async_callback_data*)&cypress_device_capture_recv_data[i].cb_data;
bool is_data_ready = false;
cb_data->transfer_data_access.lock();
is_data_ready = cb_data->is_data_ready;
cb_data->transfer_data_access.unlock();
if(cypress_device_capture_recv_data[i].in_use && is_data_ready) {
cb_data->is_data_ready = false;
cb_data->function(&cypress_device_capture_recv_data[i], cb_data->actual_length, cb_data->status_value);
}
}
}
else
cypress_driver_wait_async_transfers(cypress_device_capture_recv_data);
}
}
static bool cypress_driver_bulk_async_start(HANDLE handle, uint8_t* buffer, size_t size, DWORD* num_read, uint8_t ep_num, OVERLAPPED* overlap, CYPRESS_SINGLE_TRANSFER* single_transfer) {
memset(single_transfer, 0, sizeof(CYPRESS_SINGLE_TRANSFER));
single_transfer->ucEndpointAddress = ep_num;
bool retval = DeviceIoControl(handle, IOCTL_ADAPT_SEND_NON_EP0_DIRECT, single_transfer, sizeof(CYPRESS_SINGLE_TRANSFER), buffer, size, num_read, overlap);
return retval;
}
static bool cypress_driver_bulk_sync_start(HANDLE handle, uint8_t* buffer, size_t size, DWORD* num_read, uint8_t ep_num) {
CYPRESS_SINGLE_TRANSFER single_transfer;
return cypress_driver_bulk_async_start(handle, buffer, size, num_read, ep_num, NULL, &single_transfer);
}
static bool cypress_driver_generic_ctrl_transfer(HANDLE handle, uint8_t* buffer, size_t inner_size, uint8_t val_hi, uint8_t val_low, uint16_t index, uint16_t timeout_s, uint8_t recipient, uint8_t type, uint8_t direction, uint16_t request_code, DWORD* num_read) {
size_t full_size = inner_size + sizeof(CYPRESS_SINGLE_TRANSFER);
uint8_t* full_buffer = new uint8_t[full_size];
memset(full_buffer, 0, full_size);
CYPRESS_SINGLE_TRANSFER* single_transfer = (CYPRESS_SINGLE_TRANSFER*)full_buffer;
single_transfer->SetupPacket.bmReqType.Direction = direction;
single_transfer->SetupPacket.bmReqType.Type = type;
single_transfer->SetupPacket.bmReqType.Recipient = recipient;
single_transfer->SetupPacket.bRequest = request_code;
single_transfer->SetupPacket.wVal.hiByte = val_hi;
single_transfer->SetupPacket.wVal.lowByte = val_low;
single_transfer->SetupPacket.wIndex = index;
single_transfer->SetupPacket.wLength = inner_size;
single_transfer->SetupPacket.ulTimeOut = timeout_s;
single_transfer->BufferLength = single_transfer->SetupPacket.wLength;
single_transfer->BufferOffset = sizeof(CYPRESS_SINGLE_TRANSFER);
if(direction == DIR_HOST_TO_DEVICE)
memcpy(full_buffer + single_transfer->BufferOffset, buffer, inner_size);
bool retval = DeviceIoControl(handle, IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, full_buffer, full_size, full_buffer, full_size, num_read, NULL);
if((*num_read) >= sizeof(CYPRESS_SINGLE_TRANSFER))
*num_read -= sizeof(CYPRESS_SINGLE_TRANSFER);
else
*num_read = 0;
if(direction == DIR_DEVICE_TO_HOST)
memcpy(buffer, full_buffer + single_transfer->BufferOffset, inner_size);
delete []full_buffer;
if((*num_read) != inner_size)
return false;
return retval;
}
static bool read_cypress_driver_generic_info(HANDLE handle, uint8_t* buffer, size_t inner_size, uint8_t val_hi, uint8_t val_low, uint16_t index, DWORD* num_read) {
return cypress_driver_generic_ctrl_transfer(handle, buffer, inner_size, val_hi, val_low, index, 5, TARGET_DEVICE, REQUEST_STANDARD, DIR_DEVICE_TO_HOST, USB_REQUEST_GET_DESCRIPTOR, num_read);
}
static bool read_cypress_driver_device_info(HANDLE handle, uint8_t* buffer, size_t inner_size, DWORD* num_read) {
return read_cypress_driver_generic_info(handle, buffer, inner_size, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, num_read);
}
static bool cypress_driver_get_string_language_info(HANDLE handle, USHORT &language_id, USHORT preferred_language = 0x0409) {
USB_COMMON_DESCRIPTOR cmnDescriptor;
DWORD num_read = 0;
language_id = 0;
bool retval = read_cypress_driver_generic_info(handle, (uint8_t*)&cmnDescriptor, sizeof(cmnDescriptor), USB_STRING_DESCRIPTOR_TYPE, 0, 0, &num_read);
if(!retval)
return false;
if(cmnDescriptor.bLength == 2)
return true;
uint8_t* buffer = new uint8_t[cmnDescriptor.bLength];
retval = read_cypress_driver_generic_info(handle, buffer, cmnDescriptor.bLength, USB_STRING_DESCRIPTOR_TYPE, 0, 0, &num_read);
if(retval) {
USB_STRING_DESCRIPTOR* IDs = (USB_STRING_DESCRIPTOR*)buffer;
int num_langs = (cmnDescriptor.bLength - 2) / 2;
language_id = IDs[0].bString[0];
for(int i = 0; i < num_langs; i++)
if(IDs[i].bString[0] == preferred_language)
language_id = preferred_language;
}
delete []buffer;
return retval;
}
static bool cypress_driver_get_string_info(HANDLE handle, UCHAR string_index, USHORT language_id, std::string &out_str) {
USB_COMMON_DESCRIPTOR cmnDescriptor;
DWORD num_read = 0;
out_str = "";
bool retval = read_cypress_driver_generic_info(handle, (uint8_t*)&cmnDescriptor, sizeof(cmnDescriptor), USB_STRING_DESCRIPTOR_TYPE, string_index, language_id, &num_read);
if(!retval)
return false;
uint8_t* buffer = new uint8_t[cmnDescriptor.bLength];
retval = read_cypress_driver_generic_info(handle, buffer, cmnDescriptor.bLength, USB_STRING_DESCRIPTOR_TYPE, string_index, language_id, &num_read);
if(retval && num_read >= 2) {
uint8_t bytes = buffer[0];
if(bytes > num_read)
bytes = num_read;
uint8_t signature = buffer[1];
if((signature == 3) && (bytes > 2))
out_str = read_string(buffer, bytes - 2);
}
delete []buffer;
return retval;
}
static std::string cypress_driver_get_device_path(HDEVINFO DeviceInfoSet, SP_DEVICE_INTERFACE_DATA* DeviceInterfaceData) {
std::string result = "";
// Call this with an empty buffer to the required size of the structure.
ULONG requiredSize;
SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, DeviceInterfaceData, NULL, 0, &requiredSize, NULL);
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return result;
PSP_DEVICE_INTERFACE_DETAIL_DATA devInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(new uint8_t[requiredSize]);
if(!devInterfaceDetailData)
return result;
devInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if(SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, DeviceInterfaceData, devInterfaceDetailData, requiredSize, &requiredSize, NULL))
result = (std::string)(devInterfaceDetailData->DevicePath);
delete []((uint8_t*)devInterfaceDetailData);
return result;
}
static bool cypress_driver_get_device_pid_vid_ids(HANDLE handle, uint16_t& out_vid, uint16_t& out_pid, UCHAR &imanufacturer, UCHAR &iserial, USHORT &bcdDevice) {
if (handle == INVALID_HANDLE_VALUE)
return false;
USB_DEVICE_DESCRIPTOR out_descriptor;
memset(&out_descriptor, 0, sizeof(out_descriptor));
DWORD num_read = 0;
bool result = read_cypress_driver_device_info(handle, (uint8_t*)&out_descriptor, sizeof(USB_DEVICE_DESCRIPTOR), &num_read);
if(!result)
return false;
out_vid = out_descriptor.idVendor;
out_pid = out_descriptor.idProduct;
imanufacturer = out_descriptor.iManufacturer;
iserial = out_descriptor.iSerialNumber;
bcdDevice = out_descriptor.bcdDevice;
return true;
}
static bool cypress_driver_get_device_pid_vid_manufacturer_serial_number(std::string path, uint16_t& out_vid, uint16_t& out_pid, std::string &manufacturer, std::string &serial, uint16_t& bcd_device) {
HANDLE handle = CreateFile(path.c_str(), (GENERIC_READ | GENERIC_WRITE), (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, 0, NULL);
if (handle == INVALID_HANDLE_VALUE)
return false;
UCHAR imanufacturer;
UCHAR iserial;
if(!cypress_driver_get_device_pid_vid_ids(handle, out_vid, out_pid, imanufacturer, iserial, bcd_device)) {
CloseHandle(handle);
return false;
}
USHORT language = 0;
cypress_driver_get_string_language_info(handle, language);
cypress_driver_get_string_info(handle, imanufacturer, language, manufacturer);
cypress_driver_get_string_info(handle, iserial, language, serial);
CloseHandle(handle);
return true;
}
static bool cypress_nisetro_driver_setup_connection(cyni_device_device_handlers* handlers, std::string path, bool do_pipe_clear_reset) {
handlers->usb_handle = NULL;
handlers->mutex = NULL;
handlers->write_handle = INVALID_HANDLE_VALUE;
handlers->read_handle = INVALID_HANDLE_VALUE;
handlers->path = path;
std::string mutex_name = "Global\\ISU_" + path.substr(4);
std::replace(mutex_name.begin(), mutex_name.end(), '\\', '@');
handlers->mutex = CreateMutex(NULL, true, mutex_name.c_str());
if((handlers->mutex != NULL) && (GetLastError() == ERROR_ALREADY_EXISTS)) {
CloseHandle(handlers->mutex);
handlers->mutex = NULL;
}
if(handlers->mutex == NULL)
return false;
handlers->write_handle = CreateFile(path.c_str(), (GENERIC_READ | GENERIC_WRITE), (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
handlers->read_handle = handlers->write_handle;
if((handlers->write_handle == INVALID_HANDLE_VALUE) || (handlers->read_handle == INVALID_HANDLE_VALUE))
return false;
if(do_pipe_clear_reset) {
/*
if(!is_driver_device_reset(handlers->write_handle))
return false;
if(!is_driver_pipe_reset(handlers->write_handle))
return false;
if(!is_driver_pipe_reset(handlers->read_handle))
return false;
*/
}
return true;
}
static void cypress_nisetro_driver_close_handle(void** handle, void* default_value = INVALID_HANDLE_VALUE) {
#ifdef _WIN32
if ((*handle) == default_value)
return;
CloseHandle(*handle);
*handle = default_value;
#endif
}
static void cypress_driver_pipe_reset(HANDLE handle, uint8_t endpoint) {
DWORD dwBytes = 0;
DeviceIoControl(handle, IOCTL_ADAPT_RESET_PIPE, &endpoint, sizeof(uint8_t), NULL, 0, &dwBytes, 0);
}
#endif
cyni_device_device_handlers* cypress_driver_serial_reconnection(CaptureDevice* device) {
cyni_device_device_handlers* final_handlers = NULL;
#ifdef _WIN32
if(device->path != "") {
cyni_device_device_handlers handlers;
const cyni_device_usb_device* usb_device_info = (const cyni_device_usb_device*)device->descriptor;
if(cypress_nisetro_driver_setup_connection(&handlers, device->path, usb_device_info->do_pipe_clear_reset)) {
final_handlers = new cyni_device_device_handlers;
final_handlers->usb_handle = NULL;
final_handlers->mutex = handlers.mutex;
final_handlers->read_handle = handlers.read_handle;
final_handlers->write_handle = handlers.write_handle;
final_handlers->path = device->path;
}
else
cypress_nisetro_driver_end_connection(&handlers);
}
#endif
return final_handlers;
}
void cypress_driver_list_devices(std::vector<CaptureDevice> &devices_list, bool* not_supported_elems, int *curr_serial_extra_id_cypress, const size_t num_cypress_desc) {
#ifdef _WIN32
HDEVINFO DeviceInfoSet = SetupDiGetClassDevs(
&cypress_driver_guid,
NULL,
NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
ZeroMemory(&DeviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
uint32_t i = 0;
while(SetupDiEnumDeviceInterfaces(DeviceInfoSet, NULL, &cypress_driver_guid, i++, &DeviceInterfaceData)) {
std::string path = cypress_driver_get_device_path(DeviceInfoSet, &DeviceInterfaceData);
if (path == "")
continue;
uint16_t vid = 0;
uint16_t pid = 0;
uint16_t bcd_device = 0;
std::string manufacturer;
std::string serial;
if(!cypress_driver_get_device_pid_vid_manufacturer_serial_number(path, vid, pid, manufacturer, serial, bcd_device))
continue;
for (int j = 0; j < num_cypress_desc; j++) {
const cyni_device_usb_device* usb_device_desc = GetCyNiDeviceDesc(j);
if(not_supported_elems[j] && (usb_device_desc->vid == vid) && (usb_device_desc->pid == pid)) {
cyni_device_device_handlers handlers;
bool result_conn_check = cypress_nisetro_driver_setup_connection(&handlers, path, usb_device_desc->do_pipe_clear_reset);
cypress_nisetro_driver_end_connection(&handlers);
if(result_conn_check)
cypress_insert_device(devices_list, usb_device_desc, serial, bcd_device, curr_serial_extra_id_cypress[j], path);
break;
}
}
}
if(DeviceInfoSet)
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
#endif
}
cyni_device_device_handlers* cypress_driver_find_by_serial_number(const cyni_device_usb_device* usb_device_desc, std::string wanted_serial_number, int &curr_serial_extra_id, CaptureDevice* new_device) {
cyni_device_device_handlers* final_handlers = NULL;
#ifdef _WIN32
HDEVINFO DeviceInfoSet = SetupDiGetClassDevs(
&cypress_driver_guid,
NULL,
NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
ZeroMemory(&DeviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
uint32_t i = 0;
while(SetupDiEnumDeviceInterfaces(DeviceInfoSet, NULL, &cypress_driver_guid, i++, &DeviceInterfaceData)) {
std::string path = cypress_driver_get_device_path(DeviceInfoSet, &DeviceInterfaceData);
if (path == "")
continue;
uint16_t vid = 0;
uint16_t pid = 0;
uint16_t bcd_device = 0;
std::string manufacturer;
std::string serial;
if(!cypress_driver_get_device_pid_vid_manufacturer_serial_number(path, vid, pid, manufacturer, serial, bcd_device))
continue;
std::string read_serial = get_serial(usb_device_desc, serial, bcd_device, curr_serial_extra_id);
if((usb_device_desc->vid == vid) && (usb_device_desc->pid == pid) && (wanted_serial_number == read_serial)) {
cyni_device_device_handlers handlers;
if(cypress_nisetro_driver_setup_connection(&handlers, path, usb_device_desc->do_pipe_clear_reset)) {
final_handlers = new cyni_device_device_handlers;
final_handlers->usb_handle = NULL;
final_handlers->mutex = handlers.mutex;
final_handlers->read_handle = handlers.read_handle;
final_handlers->write_handle = handlers.write_handle;
final_handlers->path = path;
if(new_device != NULL)
*new_device = cypress_create_device(usb_device_desc, wanted_serial_number, path);
}
else
cypress_nisetro_driver_end_connection(&handlers);
break;
}
}
if(DeviceInfoSet)
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
#endif
return final_handlers;
}
int cypress_driver_ctrl_transfer_in(cyni_device_device_handlers* handlers, uint8_t* buffer, size_t inner_size, uint16_t value, uint16_t index, uint16_t request_code, int* num_read) {
#ifdef _WIN32
DWORD dummy = 0;
bool retval = cypress_driver_generic_ctrl_transfer(handlers->read_handle, buffer, inner_size, (value >> 8) & 0xFF, value & 0xFF, index, 1, TARGET_DEVICE, REQUEST_VENDOR, DIR_DEVICE_TO_HOST, request_code, &dummy);
*num_read = dummy;
return retval ? 0 : -1;
#else
return 0;
#endif
}
int cypress_driver_ctrl_transfer_out(cyni_device_device_handlers* handlers, uint8_t* buffer, size_t inner_size, uint16_t value, uint16_t index, uint16_t request_code, int* num_read) {
#ifdef _WIN32
DWORD dummy = 0;
bool retval = cypress_driver_generic_ctrl_transfer(handlers->write_handle, buffer, inner_size, (value >> 8) & 0xFF, value & 0xFF, index, 1, TARGET_DEVICE, REQUEST_VENDOR, DIR_HOST_TO_DEVICE, request_code, &dummy);
*num_read = dummy;
return retval ? 0 : -1;
#else
return 0;
#endif
}
void cypress_nisetro_driver_end_connection(cyni_device_device_handlers* handlers) {
#ifdef _WIN32
cypress_nisetro_driver_close_handle(&handlers->write_handle);
handlers->read_handle = handlers->write_handle;
cypress_nisetro_driver_close_handle(&handlers->mutex, NULL);
#endif
}
int cypress_driver_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) {
int result = LIBUSB_SUCCESS;
#ifdef _WIN32
DWORD inner_transfered = 0;
if(!cypress_driver_bulk_sync_start(handlers->read_handle, buf, length, &inner_transfered, usb_device_desc->ep_bulk_in))
result = -1;
*transferred = inner_transfered;
#endif
return result;
}
int cypress_driver_ctrl_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) {
int result = LIBUSB_SUCCESS;
#ifdef _WIN32
DWORD inner_transfered = 0;
if(!cypress_driver_bulk_sync_start(handlers->read_handle, buf, length, &inner_transfered, usb_device_desc->ep_ctrl_bulk_in))
result = -1;
*transferred = inner_transfered;
#endif
return result;
}
int cypress_driver_ctrl_bulk_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) {
int result = LIBUSB_SUCCESS;
#ifdef _WIN32
DWORD inner_transfered = 0;
if(!cypress_driver_bulk_sync_start(handlers->write_handle, buf, length, &inner_transfered, usb_device_desc->ep_ctrl_bulk_out))
result = -1;
*transferred = inner_transfered;
#endif
return result;
}
void cypress_driver_pipe_reset_ctrl_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc) {
#ifdef _WIN32
cypress_driver_pipe_reset(handlers->read_handle, usb_device_desc->ep_ctrl_bulk_in);
#endif
}
void cypress_driver_pipe_reset_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc) {
#ifdef _WIN32
cypress_driver_pipe_reset(handlers->read_handle, usb_device_desc->ep_bulk_in);
#endif
}
void cypress_driver_pipe_reset_ctrl_bulk_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc) {
#ifdef _WIN32
cypress_driver_pipe_reset(handlers->read_handle, usb_device_desc->ep_ctrl_bulk_out);
#endif
}
void cypress_driver_find_used_serial(const cyni_device_usb_device* usb_device_desc, bool* found, size_t num_free_fw_ids, int &curr_serial_extra_id) {
#ifdef _WIN32
HDEVINFO DeviceInfoSet = SetupDiGetClassDevs(
&cypress_driver_guid,
NULL,
NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
ZeroMemory(&DeviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
uint32_t i = 0;
while(SetupDiEnumDeviceInterfaces(DeviceInfoSet, NULL, &cypress_driver_guid, i++, &DeviceInterfaceData)) {
std::string path = cypress_driver_get_device_path(DeviceInfoSet, &DeviceInterfaceData);
if (path == "")
continue;
uint16_t vid = 0;
uint16_t pid = 0;
uint16_t bcd_device = 0;
std::string manufacturer;
std::string serial;
if(!cypress_driver_get_device_pid_vid_manufacturer_serial_number(path, vid, pid, manufacturer, serial, bcd_device))
continue;
std::string read_serial = get_serial(usb_device_desc, serial, bcd_device, curr_serial_extra_id);
if((usb_device_desc->vid == vid) && (usb_device_desc->pid == pid)) {
try {
int pos = std::stoi(read_serial);
if((pos < 0) || (pos >= num_free_fw_ids))
continue;
found[pos] = true;
}
catch(...) {
continue;
}
}
}
if(DeviceInfoSet)
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
#endif
}
int cypress_driver_async_in_start(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, cyni_async_callback_data* cb_data) {
#ifdef _WIN32
cb_data->transfer_data_access.lock();
cb_data->transfer_data = cb_data->base_transfer_data;
cb_data->handle = handlers->read_handle;
cb_data->requested_length = length;
cb_data->buffer = buf;
cb_data->start_request = std::chrono::high_resolution_clock::now();
cb_data->timeout_s = usb_device_desc->bulk_timeout / 1000.0;
OVERLAPPED* overlap_data = (OVERLAPPED*)cb_data->transfer_data;
cb_data->is_transfer_done_mutex->specific_try_lock(cb_data->internal_index);
int retval = cypress_driver_bulk_async_start(cb_data->handle, cb_data->buffer, cb_data->requested_length, NULL, usb_device_desc->ep_bulk_in, overlap_data, (CYPRESS_SINGLE_TRANSFER*)cb_data->extra_transfer_data);
cb_data->transfer_data_access.unlock();
if(!retval) {
int error = GetLastError();
if(error != ERROR_IO_PENDING)
return LIBUSB_ERROR_BUSY;
}
#endif
return LIBUSB_SUCCESS;
}
void cypress_driver_start_thread(std::thread* thread_ptr, bool* usb_thread_run, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, cyni_device_device_handlers* handlers, ConsumerMutex* AsyncMutexPtr) {
#ifdef _WIN32
*usb_thread_run = true;
for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) {
cypress_device_capture_recv_data[i].cb_data.extra_transfer_data = new CYPRESS_SINGLE_TRANSFER;
cypress_device_capture_recv_data[i].cb_data.base_transfer_data = new OVERLAPPED;
((OVERLAPPED*)cypress_device_capture_recv_data[i].cb_data.base_transfer_data)->hEvent = CreateEvent(NULL, false, false, NULL);
}
*thread_ptr = std::thread(cypress_driver_function, usb_thread_run, cypress_device_capture_recv_data, handlers);
#endif
}
void cypress_driver_close_thread(std::thread* thread_ptr, bool* usb_thread_run, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) {
#ifdef _WIN32
*usb_thread_run = false;
thread_ptr->join();
for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) {
CloseHandle(((OVERLAPPED*)cypress_device_capture_recv_data[i].cb_data.base_transfer_data)->hEvent);
delete ((OVERLAPPED*)cypress_device_capture_recv_data[i].cb_data.base_transfer_data);
delete ((CYPRESS_SINGLE_TRANSFER*)cypress_device_capture_recv_data[i].cb_data.extra_transfer_data);
}
#endif
}
void cypress_driver_cancel_callback(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, cyni_async_callback_data* cb_data) {
#ifdef _WIN32
DWORD transferred = 0;
OVERLAPPED ov;
memset(&ov, 0, sizeof(OVERLAPPED));
ov.hEvent = CreateEvent(NULL, false, false, NULL);
uint8_t pipe = usb_device_desc->ep_bulk_in;
bool ret = DeviceIoControl(handlers->read_handle, IOCTL_ADAPT_ABORT_PIPE, &pipe, sizeof(uint8_t), NULL, 0, &transferred, &ov);
if((!ret) && (GetLastError() == ERROR_IO_PENDING))
WaitForSingleObject(ov.hEvent, INFINITE);
CloseHandle(ov.hEvent);
#endif
}
void cypress_driver_set_transfer_size_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, size_t new_transfer_size) {
#ifdef _WIN32
DWORD transferred;
CYPRESS_SET_TRANSFER_SIZE_INFO SetTransferInfo;
new_transfer_size = ((new_transfer_size + usb_device_desc->max_usb_packet_size - 1) / usb_device_desc->max_usb_packet_size) * usb_device_desc->max_usb_packet_size;
SetTransferInfo.EndpointAddress = usb_device_desc->ep_bulk_in;
SetTransferInfo.TransferSize = new_transfer_size;
DeviceIoControl(handlers->read_handle, IOCTL_ADAPT_SET_TRANSFER_SIZE, &SetTransferInfo, sizeof(CYPRESS_SET_TRANSFER_SIZE_INFO), &SetTransferInfo, sizeof(CYPRESS_SET_TRANSFER_SIZE_INFO), &transferred, NULL);
#endif
}

View File

@@ -0,0 +1,264 @@
#include "cypress_nisetro_libusb_comms.hpp"
#include "cypress_nisetro_acquisition_general.hpp"
#include <cstring>
#include <libusb.h>
#include "usb_generic.hpp"
static void cypress_device_usb_thread_function(bool* usb_thread_run) {
if(!usb_is_initialized())
return;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 300000;
while(*usb_thread_run)
libusb_handle_events_timeout_completed(get_usb_ctx(), &tv, NULL);
}
void cypress_libusb_start_thread(std::thread* thread_ptr, bool* usb_thread_run) {
if(!usb_is_initialized())
return;
*usb_thread_run = true;
*thread_ptr = std::thread(cypress_device_usb_thread_function, usb_thread_run);
}
void cypress_libusb_close_thread(std::thread* thread_ptr, bool* usb_thread_run) {
if(!usb_is_initialized())
return;
*usb_thread_run = false;
thread_ptr->join();
}
// Read from ctrl_in
int cypress_libusb_ctrl_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, uint8_t request, uint16_t value, uint16_t index, int* transferred) {
int ret = libusb_control_transfer(handlers->usb_handle, 0xC0, request, value, index, buf, length, usb_device_desc->bulk_timeout);
if(ret >= 0)
*transferred = ret;
return ret;
}
// Write to ctrl_out
int cypress_libusb_ctrl_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, uint8_t request, uint16_t value, uint16_t index, int* transferred) {
int ret = libusb_control_transfer(handlers->usb_handle, 0x40, request, value, index, buf, length, usb_device_desc->bulk_timeout);
if(ret >= 0)
*transferred = ret;
return ret;
}
// Read from bulk
int cypress_libusb_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) {
return libusb_bulk_transfer(handlers->usb_handle, usb_device_desc->ep_bulk_in, buf, length, transferred, usb_device_desc->bulk_timeout);
}
// Read from ctrl bulk
int cypress_libusb_ctrl_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) {
return libusb_bulk_transfer(handlers->usb_handle, usb_device_desc->ep_ctrl_bulk_in, buf, length, transferred, usb_device_desc->bulk_timeout);
}
// Write to ctrl bulk
int cypress_libusb_ctrl_bulk_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) {
return libusb_bulk_transfer(handlers->usb_handle, usb_device_desc->ep_ctrl_bulk_out, buf, length, transferred, usb_device_desc->bulk_timeout);
}
void cypress_libusb_pipe_reset_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc) {
libusb_clear_halt(handlers->usb_handle, usb_device_desc->ep_bulk_in);
}
void cypress_libusb_pipe_reset_ctrl_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc) {
libusb_clear_halt(handlers->usb_handle, usb_device_desc->ep_ctrl_bulk_in);
}
void cypress_libusb_pipe_reset_ctrl_bulk_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc) {
libusb_clear_halt(handlers->usb_handle, usb_device_desc->ep_ctrl_bulk_out);
}
void cypress_libusb_cancell_callback(cyni_async_callback_data* cb_data) {
cb_data->transfer_data_access.lock();
if(cb_data->transfer_data)
libusb_cancel_transfer((libusb_transfer*)cb_data->transfer_data);
cb_data->transfer_data_access.unlock();
}
void STDCALL cypress_libusb_async_callback(libusb_transfer* transfer) {
cyni_async_callback_data* cb_data = (cyni_async_callback_data*)transfer->user_data;
cb_data->transfer_data_access.lock();
cb_data->transfer_data = NULL;
cb_data->is_transfer_done_mutex->specific_unlock(cb_data->internal_index);
cb_data->transfer_data_access.unlock();
cb_data->function(cb_data->actual_user_data, transfer->actual_length, transfer->status);
}
// Read from bulk
int cypress_libusb_async_in_start(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, cyni_async_callback_data* cb_data) {
libusb_transfer *transfer_in = libusb_alloc_transfer(0);
if(!transfer_in)
return LIBUSB_ERROR_OTHER;
cb_data->transfer_data_access.lock();
cb_data->transfer_data = transfer_in;
cb_data->is_transfer_done_mutex->specific_try_lock(cb_data->internal_index);
libusb_fill_bulk_transfer(transfer_in, handlers->usb_handle, usb_device_desc->ep_bulk_in, buf, length, cypress_libusb_async_callback, cb_data, usb_device_desc->bulk_timeout);
transfer_in->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
int retval = libusb_submit_transfer(transfer_in);
cb_data->transfer_data_access.unlock();
return retval;
}
static bool cypress_libusb_setup_connection(libusb_device_handle* handle, const cyni_device_usb_device* usb_device_desc) {
int result = libusb_kernel_driver_active(handle, usb_device_desc->default_interface);
if(result == 1)
libusb_detach_kernel_driver(handle, usb_device_desc->default_interface);
result = libusb_set_configuration(handle, usb_device_desc->default_config);
if(result != LIBUSB_SUCCESS)
return false;
result = libusb_kernel_driver_active(handle, usb_device_desc->default_interface);
if(result == 1)
libusb_detach_kernel_driver(handle, usb_device_desc->default_interface);
result = libusb_claim_interface(handle, usb_device_desc->default_interface);
if(result != LIBUSB_SUCCESS)
return false;
if(usb_device_desc->alt_interface != 0) {
result = libusb_set_interface_alt_setting(handle, usb_device_desc->default_interface, usb_device_desc->alt_interface);
if(result != LIBUSB_SUCCESS)
return false;
}
return true;
}
static void read_strings(libusb_device_handle *handle, libusb_device_descriptor *usb_descriptor, char* manufacturer, char* serial) {
manufacturer[0] = 0;
serial[0] = 0;
libusb_get_string_descriptor_ascii(handle, usb_descriptor->iManufacturer, (uint8_t*)manufacturer, 0x100);
libusb_get_string_descriptor_ascii(handle, usb_descriptor->iSerialNumber, (uint8_t*)serial, 0x100);
manufacturer[0xFF] = 0;
serial[0xFF] = 0;
}
static int cypress_libusb_insert_device(std::vector<CaptureDevice> &devices_list, const cyni_device_usb_device* usb_device_desc, libusb_device *usb_device, libusb_device_descriptor *usb_descriptor, int &curr_serial_extra_id) {
libusb_device_handle *handle = NULL;
if((usb_descriptor->idVendor != usb_device_desc->vid) || (usb_descriptor->idProduct != usb_device_desc->pid))
return LIBUSB_ERROR_NOT_FOUND;
int result = libusb_open(usb_device, &handle);
if((result < 0) || (handle == NULL))
return result;
char manufacturer[0x100];
char serial[0x100];
read_strings(handle, usb_descriptor, manufacturer, serial);
bool result_setup = cypress_libusb_setup_connection(handle, usb_device_desc);
if(result_setup)
cypress_insert_device(devices_list, usb_device_desc, (std::string)(serial), usb_descriptor->bcdDevice, curr_serial_extra_id);
libusb_release_interface(handle, usb_device_desc->default_interface);
libusb_close(handle);
return result;
}
cyni_device_device_handlers* cypress_libusb_serial_reconnection(const cyni_device_usb_device* usb_device_desc, std::string wanted_serial_number, int &curr_serial_extra_id, CaptureDevice* new_device) {
if(!usb_is_initialized())
return NULL;
libusb_device **usb_devices;
int num_devices = libusb_get_device_list(get_usb_ctx(), &usb_devices);
libusb_device_descriptor usb_descriptor{};
cyni_device_device_handlers* final_handlers = NULL;
for(int i = 0; i < num_devices; i++) {
cyni_device_device_handlers handlers;
int result = libusb_get_device_descriptor(usb_devices[i], &usb_descriptor);
if(result < 0)
continue;
if((usb_descriptor.idVendor != usb_device_desc->vid) || (usb_descriptor.idProduct != usb_device_desc->pid))
continue;
result = libusb_open(usb_devices[i], &handlers.usb_handle);
if(result || (handlers.usb_handle == NULL))
continue;
char manufacturer[0x100];
char serial[0x100];
read_strings(handlers.usb_handle, &usb_descriptor, manufacturer, serial);
std::string device_serial_number = get_serial(usb_device_desc, (std::string)(serial), usb_descriptor.bcdDevice, curr_serial_extra_id);
if((wanted_serial_number == device_serial_number) && (cypress_libusb_setup_connection(handlers.usb_handle, usb_device_desc))) {
final_handlers = new cyni_device_device_handlers;
final_handlers->usb_handle = handlers.usb_handle;
if(new_device != NULL)
*new_device = cypress_create_device(usb_device_desc, wanted_serial_number);
break;
}
libusb_close(handlers.usb_handle);
}
if(num_devices >= 0)
libusb_free_device_list(usb_devices, 1);
return final_handlers;
}
void cypress_libusb_end_connection(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device_desc, bool interface_claimed) {
if (interface_claimed)
libusb_release_interface(handlers->usb_handle, device_desc->default_interface);
libusb_close(handlers->usb_handle);
handlers->usb_handle = NULL;
}
void cypress_libusb_find_used_serial(const cyni_device_usb_device* usb_device_desc, bool* found, size_t num_free_fw_ids, int &curr_serial_extra_id) {
if(!usb_is_initialized())
return;
libusb_device **usb_devices;
int num_devices = libusb_get_device_list(get_usb_ctx(), &usb_devices);
libusb_device_descriptor usb_descriptor{};
cyni_device_device_handlers* final_handlers = NULL;
for(int i = 0; i < num_devices; i++) {
cyni_device_device_handlers handlers;
int result = libusb_get_device_descriptor(usb_devices[i], &usb_descriptor);
if(result < 0)
continue;
if((usb_descriptor.idVendor != usb_device_desc->vid) || (usb_descriptor.idProduct != usb_device_desc->pid))
continue;
result = libusb_open(usb_devices[i], &handlers.usb_handle);
if(result || (handlers.usb_handle == NULL))
continue;
char manufacturer[0x100];
char serial[0x100];
read_strings(handlers.usb_handle, &usb_descriptor, manufacturer, serial);
libusb_close(handlers.usb_handle);
std::string device_serial_number = get_serial(usb_device_desc, (std::string)(serial), usb_descriptor.bcdDevice, curr_serial_extra_id);
try {
int pos = std::stoi(device_serial_number);
if((pos < 0) || (pos >= num_free_fw_ids))
continue;
found[pos] = true;
}
catch(...) {
continue;
}
}
if(num_devices >= 0)
libusb_free_device_list(usb_devices, 1);
return;
}
void cypress_libusb_list_devices(std::vector<CaptureDevice> &devices_list, bool* no_access_elems, bool* not_supported_elems, int *curr_serial_extra_id_cypress, const size_t num_cypress_desc) {
if(!usb_is_initialized())
return;
libusb_device **usb_devices;
int num_devices = libusb_get_device_list(get_usb_ctx(), &usb_devices);
libusb_device_descriptor usb_descriptor{};
for(int i = 0; i < num_devices; i++) {
int result = libusb_get_device_descriptor(usb_devices[i], &usb_descriptor);
if(result < 0)
continue;
for (int j = 0; j < num_cypress_desc; j++) {
result = cypress_libusb_insert_device(devices_list, GetCyNiDeviceDesc(j), usb_devices[i], &usb_descriptor, curr_serial_extra_id_cypress[j]);
if (result != LIBUSB_ERROR_NOT_FOUND) {
if (result == LIBUSB_ERROR_ACCESS)
no_access_elems[j] = true;
if (result == LIBUSB_ERROR_NOT_SUPPORTED)
not_supported_elems[j] = true;
break;
}
}
}
if(num_devices >= 0)
libusb_free_device_list(usb_devices, 1);
}

View File

@@ -207,6 +207,20 @@ inline static void to_8_bit_6(uint8_t* out, uint8_t* in) {
out[2] = to_8_bit_6(in[2]);
}
static void usb_cypress_nisetro_ds_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_out) {
int pos_top = 0;
int pos_bottom = WIDTH_DS * HEIGHT_DS * 3;
uint8_t* data_in = (uint8_t*)p_in->cypress_nisetro_capture_received.video_in.screen_data;
uint8_t* data_out = (uint8_t*)p_out->screen_data;
for(int i = 0; i < sizeof(CypressNisetroDSCaptureReceived); i++) {
uint8_t conv = to_8_bit_6(data_in[i]);
if(data_in[i] & 0x40)
data_out[pos_bottom++] = conv;
else
data_out[pos_top++] = conv;
}
}
static void usb_is_device_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_out, CaptureStatus* status, CaptureScreensType capture_type) {
bool is_nitro = true;
#ifdef USE_IS_DEVICES_USB
@@ -284,6 +298,12 @@ bool convertVideoToOutput(VideoOutputData *p_out, const bool is_big_endian, Capt
converted = true;
}
#endif
#ifdef USE_CYNI_USB
if(chosen_device->cc_type == CAPTURE_CONN_CYPRESS_NISETRO) {
usb_cypress_nisetro_ds_convertVideoToOutput(p_in, p_out);
converted = true;
}
#endif
return converted;
}

View File

@@ -3,6 +3,7 @@
#include "dscapture_ftd2_shared.hpp"
#include "usb_ds_3ds_capture.hpp"
#include "usb_is_device_acquisition.hpp"
#include "cypress_nisetro_acquisition.hpp"
#include <vector>
#include <thread>
@@ -78,6 +79,9 @@ bool connect(bool print_failed, CaptureData* capture_data, FrontendData* fronten
// Device Listing
std::vector<CaptureDevice> devices_list;
std::vector<no_access_recap_data> no_access_list;
#ifdef USE_CYNI_USB
list_devices_cyni_device(devices_list, no_access_list);
#endif
#ifdef USE_FTD3
list_devices_ftd3(devices_list, no_access_list);
#endif
@@ -115,6 +119,10 @@ bool connect(bool print_failed, CaptureData* capture_data, FrontendData* fronten
}
// Actual connection
#ifdef USE_CYNI_USB
if((devices_list[chosen_device].cc_type == CAPTURE_CONN_CYPRESS_NISETRO) && (!cyni_device_connect_usb(print_failed, capture_data, &devices_list[chosen_device])))
return false;
#endif
#ifdef USE_FTD3
if((devices_list[chosen_device].cc_type == CAPTURE_CONN_FTD3) && (!connect_ftd3(print_failed, capture_data, &devices_list[chosen_device])))
return false;
@@ -151,6 +159,10 @@ void captureCall(CaptureData* capture_data) {
}
// Main capture loop
#ifdef USE_CYNI_USB
if(capture_data->status.device.cc_type == CAPTURE_CONN_CYPRESS_NISETRO)
cyni_device_acquisition_main_loop(capture_data);
#endif
#ifdef USE_FTD3
if(capture_data->status.device.cc_type == CAPTURE_CONN_FTD3)
ftd3_capture_main_loop(capture_data);
@@ -177,6 +189,10 @@ void captureCall(CaptureData* capture_data) {
capture_data->status.audio_wait.unlock();
// Capture cleanup
#ifdef USE_CYNI_USB
if(capture_data->status.device.cc_type == CAPTURE_CONN_CYPRESS_NISETRO)
usb_cyni_device_acquisition_cleanup(capture_data);
#endif
#ifdef USE_FTD3
if(capture_data->status.device.cc_type == CAPTURE_CONN_FTD3)
ftd3_capture_cleanup(capture_data);
@@ -214,6 +230,10 @@ uint64_t get_audio_n_samples(CaptureData* capture_data, uint64_t read) {
}
uint64_t get_video_in_size(CaptureData* capture_data) {
#ifdef USE_CYNI_USB
if(capture_data->status.device.cc_type == CAPTURE_CONN_CYPRESS_NISETRO)
return cyni_device_get_video_in_size(capture_data);
#endif
#ifdef USE_FTD3
if(capture_data->status.device.cc_type == CAPTURE_CONN_FTD3)
return ftd3_get_video_in_size(capture_data);
@@ -251,6 +271,9 @@ void capture_init() {
#ifdef USE_FTD2
ftd2_init_shared();
#endif
#ifdef USE_CYNI_USB
usb_cyni_device_init();
#endif
}
void capture_close() {
@@ -263,4 +286,7 @@ void capture_close() {
#ifdef USE_FTD2
ftd2_end_shared();
#endif
#ifdef USE_CYNI_USB
usb_cyni_device_close();
#endif
}

View File

@@ -0,0 +1,2 @@
SUBSYSTEM=="usb", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="8613", MODE="0666"
SUBSYSTEM=="usb", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="1004", MODE="0666"