mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-12-23 17:06:02 +00:00
Additional USB changes.
This commit is contained in:
parent
97f7a46a91
commit
61fb465e2a
3 changed files with 124 additions and 79 deletions
|
@ -22,7 +22,6 @@
|
|||
#include <dirent.h>
|
||||
#include <threads.h>
|
||||
#include <stdarg.h>
|
||||
#include <malloc.h>
|
||||
|
||||
//#include "lvgl_helper.h"
|
||||
|
||||
|
@ -150,7 +149,7 @@ static int read_thread_func(void *arg)
|
|||
return -1;
|
||||
}
|
||||
|
||||
u8 *buf = memalign(USB_TRANSFER_ALIGNMENT, TEST_BUF_SIZE);
|
||||
u8 *buf = usbAllocatePageAlignedBuffer(TEST_BUF_SIZE);
|
||||
if (!buf)
|
||||
{
|
||||
shared_data->read_error = true;
|
||||
|
@ -268,7 +267,10 @@ int main(int argc, char *argv[])
|
|||
|
||||
Result rc = 0;
|
||||
|
||||
mkdir("sdmc:/nxdt_test", 0744);
|
||||
ThreadSharedData shared_data = {0};
|
||||
thrd_t read_thread, write_thread;
|
||||
|
||||
//mkdir("sdmc:/nxdt_test", 0744);
|
||||
|
||||
// SSBU's Base Program NCA
|
||||
NcmContentInfo base_program_content_info = {
|
||||
|
@ -330,7 +332,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
consolePrint("ncm open storage succeeded\n");
|
||||
|
||||
if (!ncaInitializeContext(base_nca_ctx, NcmStorageId_SdCard, &ncm_storage, 0, &base_program_content_info, &base_tik))
|
||||
/*if (!ncaInitializeContext(base_nca_ctx, NcmStorageId_SdCard, &ncm_storage, 0, &base_program_content_info, &base_tik))
|
||||
{
|
||||
consolePrint("base nca initialize ctx failed\n");
|
||||
goto out2;
|
||||
|
@ -390,7 +392,7 @@ int main(int argc, char *argv[])
|
|||
goto out2;
|
||||
}
|
||||
|
||||
consolePrint("bktr get file entry by path success: %.*s | 0x%lX\n", bktr_file_entry->name_length, bktr_file_entry->name, bktr_file_entry->size);
|
||||
consolePrint("bktr get file entry by path success: %.*s | 0x%lX\n", bktr_file_entry->name_length, bktr_file_entry->name, bktr_file_entry->size);*/
|
||||
|
||||
|
||||
|
||||
|
@ -414,7 +416,17 @@ int main(int argc, char *argv[])
|
|||
|
||||
consolePrint("open concatenationfile success\n");*/
|
||||
|
||||
ThreadSharedData shared_data = {0};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
consolePrint("waiting for gamecard to be ready...\n");
|
||||
|
||||
while(appletMainLoop())
|
||||
{
|
||||
if (gamecardIsReady()) break;
|
||||
}
|
||||
|
||||
//shared_data.fileobj = tmp_file;
|
||||
shared_data.fileobj = NULL;
|
||||
|
@ -425,36 +437,24 @@ int main(int argc, char *argv[])
|
|||
|
||||
consolePrint("waiting for usb connection... ");
|
||||
|
||||
u8 count = 0;
|
||||
|
||||
while(appletMainLoop())
|
||||
if (!usbPerformHandshake())
|
||||
{
|
||||
/* Avoid using usbIsHostAvailable() alone inside a loop, because it can hang up the system */
|
||||
consolePrint("%u ", count);
|
||||
if (usbIsHostAvailable()) break;
|
||||
utilsSleep(1);
|
||||
count++;
|
||||
if (count == 10) break;
|
||||
}
|
||||
|
||||
if (count == 10)
|
||||
{
|
||||
consolePrint("\nusb connection not detected\n");
|
||||
consolePrint("failed\n");
|
||||
goto out2;
|
||||
}
|
||||
|
||||
consolePrint("\nusb connection detected\n");
|
||||
consolePrint("success\n");
|
||||
|
||||
consolePrint("sending file properties... ");
|
||||
|
||||
if (!usbSendFileProperties(shared_data.total_size, "gamecard.xci"))
|
||||
{
|
||||
consolePrint("usb send file properties failed\n");
|
||||
consolePrint("failed\n");
|
||||
goto out2;
|
||||
}
|
||||
|
||||
consolePrint("usb send file properties succeeded\n");
|
||||
consolePrint("success\n");
|
||||
|
||||
thrd_t read_thread, write_thread;
|
||||
|
||||
consolePrint("creating threads\n\n");
|
||||
thrd_create(&read_thread, read_thread_func, &shared_data);
|
||||
thrd_create(&write_thread, write_thread_func, &shared_data);
|
||||
|
@ -475,12 +475,12 @@ int main(int argc, char *argv[])
|
|||
|
||||
if (prev_time == ts->tm_sec || prev_size == size) continue;
|
||||
|
||||
percent = (u8)((size * 100) / shared_data.total_size) + 1;
|
||||
percent = (u8)((size * 100) / shared_data.total_size);
|
||||
|
||||
prev_time = ts->tm_sec;
|
||||
prev_size = size;
|
||||
|
||||
printf("%lu / %lu (%u%%) | Time elapsed: %lu\n", size, shared_data.total_size, percent, (time(NULL) - start));
|
||||
printf("%lu / %lu (%u%%) | Time elapsed: %lu\n", size, shared_data.total_size, percent, (now - start));
|
||||
consoleUpdate(NULL);
|
||||
}
|
||||
|
||||
|
@ -514,6 +514,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
|
||||
out2:
|
||||
consolePrint("press any button to exit\n");
|
||||
utilsWaitForButtonPress();
|
||||
|
||||
if (tmp_file) fclose(tmp_file);
|
||||
|
|
134
source/usb.c
134
source/usb.c
|
@ -19,6 +19,7 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "usb.h"
|
||||
#include "utils.h"
|
||||
|
@ -27,7 +28,8 @@
|
|||
|
||||
#define USB_CMD_HEADER_MAGIC 0x4E584454 /* "NXDT" */
|
||||
|
||||
#define USB_TRANSFER_TIMEOUT (u64)30000000000 /* 10 seconds (in nanoseconds) */
|
||||
#define USB_TRANSFER_ALIGNMENT 0x1000 /* 4 KiB */
|
||||
#define USB_TRANSFER_TIMEOUT 30 /* 30 seconds */
|
||||
|
||||
/* Type definitions. */
|
||||
|
||||
|
@ -68,17 +70,17 @@ typedef struct {
|
|||
} UsbCommandSendFileProperties;
|
||||
|
||||
typedef enum {
|
||||
UsbStatusType_Success = 0,
|
||||
UsbStatusType_Success = 0,
|
||||
|
||||
UsbStatusType_InvalidCommandSize = 1,
|
||||
UsbStatusType_WriteCommandFailed = 2,
|
||||
UsbStatusType_ReadStatusFailed = 3,
|
||||
UsbStatusType_InvalidMagicWord = 4,
|
||||
UsbStatusType_InvalidCommandSize = 1,
|
||||
UsbStatusType_WriteCommandFailed = 2,
|
||||
UsbStatusType_ReadStatusFailed = 3,
|
||||
UsbStatusType_InvalidMagicWord = 4,
|
||||
|
||||
UsbStatusType_MalformedCommand = 5,
|
||||
UsbStatusType_UnsupportedAbiVersion = 6,
|
||||
UsbStatusType_UnsupportedCommand = 7,
|
||||
UsbStatusType_HostIoError = 8
|
||||
UsbStatusType_MalformedCommand = 5,
|
||||
UsbStatusType_UnsupportedAbiVersion = 6,
|
||||
UsbStatusType_UnsupportedCommand = 7,
|
||||
UsbStatusType_HostIoError = 8
|
||||
} UsbStatusType;
|
||||
|
||||
typedef struct {
|
||||
|
@ -98,6 +100,8 @@ static u64 g_usbTransferRemainingSize = 0;
|
|||
|
||||
/* Function prototypes. */
|
||||
|
||||
static bool _usbPerformHandshake(void);
|
||||
|
||||
NX_INLINE void usbPrepareCommandHeader(u32 cmd, u32 cmd_block_size);
|
||||
static u32 usbSendCommand(size_t cmd_size);
|
||||
NX_INLINE void usbLogStatusDetail(u32 status);
|
||||
|
@ -114,8 +118,10 @@ NX_INLINE bool usbInitializeDeviceInterface(void);
|
|||
static bool usbInitializeDeviceInterface5x(void);
|
||||
static bool usbInitializeDeviceInterface1x(void);
|
||||
|
||||
static bool usbRead(void *buf, size_t size);
|
||||
static bool usbWrite(void *buf, size_t size);
|
||||
NX_INLINE bool usbIsHostAvailable(void);
|
||||
|
||||
NX_INLINE bool usbRead(void *buf, size_t size);
|
||||
NX_INLINE bool usbWrite(void *buf, size_t size);
|
||||
static bool usbTransferData(void *buf, size_t size, UsbDsEndpoint *endpoint);
|
||||
|
||||
bool usbInitialize(void)
|
||||
|
@ -159,11 +165,10 @@ void usbExit(void)
|
|||
rwlockWriteUnlock(&g_usbDeviceLock);
|
||||
}
|
||||
|
||||
bool usbIsHostAvailable(void)
|
||||
void *usbAllocatePageAlignedBuffer(size_t size)
|
||||
{
|
||||
u32 state = 0;
|
||||
usbDsGetState(&state);
|
||||
return (state == 5);
|
||||
if (!size) return NULL;
|
||||
return memalign(USB_TRANSFER_ALIGNMENT, size);
|
||||
}
|
||||
|
||||
bool usbPerformHandshake(void)
|
||||
|
@ -172,34 +177,23 @@ bool usbPerformHandshake(void)
|
|||
rwlockWriteLock(&(g_usbDeviceInterface.lock));
|
||||
|
||||
bool ret = false;
|
||||
UsbCommandPerformHandshake *cmd_block = NULL;
|
||||
size_t cmd_size = 0;
|
||||
u32 status = UsbStatusType_Success;
|
||||
time_t start = time(NULL);
|
||||
time_t now = start;
|
||||
|
||||
if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInitialized || !g_usbDeviceInterface.initialized)
|
||||
while((now - start) < USB_TRANSFER_TIMEOUT)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
goto exit;
|
||||
if (usbIsHostAvailable())
|
||||
{
|
||||
/* Once the console has been connected to a host device, there's no need to keep running this loop */
|
||||
/* usbTransferData() implements its own timeout */
|
||||
ret = _usbPerformHandshake();
|
||||
break;
|
||||
}
|
||||
|
||||
utilsSleep(1);
|
||||
now = time(NULL);
|
||||
}
|
||||
|
||||
usbPrepareCommandHeader(UsbCommandType_PerformHandshake, (u32)sizeof(UsbCommandPerformHandshake));
|
||||
|
||||
cmd_block = (UsbCommandPerformHandshake*)(g_usbTransferBuffer + sizeof(UsbCommandHeader));
|
||||
memset(cmd_block, 0, sizeof(UsbCommandPerformHandshake));
|
||||
|
||||
cmd_block->app_ver_major = VERSION_MAJOR;
|
||||
cmd_block->app_ver_minor = VERSION_MINOR;
|
||||
cmd_block->app_ver_micro = VERSION_MICRO;
|
||||
cmd_block->abi_version = USB_ABI_VERSION;
|
||||
|
||||
cmd_size = (sizeof(UsbCommandHeader) + sizeof(UsbCommandPerformHandshake));
|
||||
|
||||
status = usbSendCommand(cmd_size);
|
||||
if (status != UsbStatusType_Success) usbLogStatusDetail(status);
|
||||
|
||||
ret = (status == UsbStatusType_Success);
|
||||
|
||||
exit:
|
||||
rwlockWriteUnlock(&(g_usbDeviceInterface.lock));
|
||||
rwlockWriteUnlock(&g_usbDeviceLock);
|
||||
|
||||
|
@ -251,7 +245,7 @@ exit:
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool usbSendFileData(void *data, u32 data_size)
|
||||
bool usbSendFileData(void *data, u64 data_size)
|
||||
{
|
||||
rwlockWriteLock(&g_usbDeviceLock);
|
||||
rwlockWriteLock(&(g_usbDeviceInterface.lock));
|
||||
|
@ -317,6 +311,36 @@ exit:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool _usbPerformHandshake(void)
|
||||
{
|
||||
UsbCommandPerformHandshake *cmd_block = NULL;
|
||||
size_t cmd_size = 0;
|
||||
u32 status = UsbStatusType_Success;
|
||||
|
||||
if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInitialized || !g_usbDeviceInterface.initialized)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
usbPrepareCommandHeader(UsbCommandType_PerformHandshake, (u32)sizeof(UsbCommandPerformHandshake));
|
||||
|
||||
cmd_block = (UsbCommandPerformHandshake*)(g_usbTransferBuffer + sizeof(UsbCommandHeader));
|
||||
memset(cmd_block, 0, sizeof(UsbCommandPerformHandshake));
|
||||
|
||||
cmd_block->app_ver_major = VERSION_MAJOR;
|
||||
cmd_block->app_ver_minor = VERSION_MINOR;
|
||||
cmd_block->app_ver_micro = VERSION_MICRO;
|
||||
cmd_block->abi_version = USB_ABI_VERSION;
|
||||
|
||||
cmd_size = (sizeof(UsbCommandHeader) + sizeof(UsbCommandPerformHandshake));
|
||||
|
||||
status = usbSendCommand(cmd_size);
|
||||
if (status != UsbStatusType_Success) usbLogStatusDetail(status);
|
||||
|
||||
return (status == UsbStatusType_Success);
|
||||
}
|
||||
|
||||
NX_INLINE void usbPrepareCommandHeader(u32 cmd, u32 cmd_block_size)
|
||||
{
|
||||
if (cmd > UsbCommandType_SendNspHeader) return;
|
||||
|
@ -518,6 +542,19 @@ static bool usbInitializeComms(void)
|
|||
rc = usbDsSetBinaryObjectStore(bos, sizeof(bos));
|
||||
if (R_FAILED(rc)) LOGFILE("usbDsSetBinaryObjectStore failed! (0x%08X)", rc);
|
||||
}
|
||||
} else {
|
||||
static const UsbDsDeviceInfo device_info = {
|
||||
.idVendor = 0x057e,
|
||||
.idProduct = 0x3000,
|
||||
.bcdDevice = 0x0100,
|
||||
.Manufacturer = APP_AUTHOR,
|
||||
.Product = APP_TITLE,
|
||||
.SerialNumber = APP_VERSION
|
||||
};
|
||||
|
||||
/* Set VID, PID and BCD */
|
||||
rc = usbDsSetVidPidBcd(&device_info);
|
||||
if (R_FAILED(rc)) LOGFILE("usbDsSetVidPidBcd failed! (0x%08X)", rc);
|
||||
}
|
||||
|
||||
if (R_FAILED(rc)) goto exit;
|
||||
|
@ -822,7 +859,14 @@ static bool usbInitializeDeviceInterface1x(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool usbRead(void *buf, size_t size)
|
||||
NX_INLINE bool usbIsHostAvailable(void)
|
||||
{
|
||||
u32 state = 0;
|
||||
Result rc = usbDsGetState(&state);
|
||||
return (R_SUCCEEDED(rc) && state == 5);
|
||||
}
|
||||
|
||||
NX_INLINE bool usbRead(void *buf, u64 size)
|
||||
{
|
||||
rwlockWriteLock(&(g_usbDeviceInterface.lock_out));
|
||||
bool ret = usbTransferData(buf, size, g_usbDeviceInterface.endpoint_out);
|
||||
|
@ -830,7 +874,7 @@ static bool usbRead(void *buf, size_t size)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool usbWrite(void *buf, size_t size)
|
||||
NX_INLINE bool usbWrite(void *buf, u64 size)
|
||||
{
|
||||
rwlockWriteLock(&(g_usbDeviceInterface.lock_in));
|
||||
bool ret = usbTransferData(buf, size, g_usbDeviceInterface.endpoint_in);
|
||||
|
@ -838,7 +882,7 @@ static bool usbWrite(void *buf, size_t size)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool usbTransferData(void *buf, size_t size, UsbDsEndpoint *endpoint)
|
||||
static bool usbTransferData(void *buf, u64 size, UsbDsEndpoint *endpoint)
|
||||
{
|
||||
if (!buf || ((u64)buf & (USB_TRANSFER_ALIGNMENT - 1)) > 0 || !size || !endpoint)
|
||||
{
|
||||
|
@ -866,7 +910,7 @@ static bool usbTransferData(void *buf, size_t size, UsbDsEndpoint *endpoint)
|
|||
}
|
||||
|
||||
/* Wait for the transfer to finish */
|
||||
rc = eventWait(&(endpoint->CompletionEvent), USB_TRANSFER_TIMEOUT);
|
||||
rc = eventWait(&(endpoint->CompletionEvent), USB_TRANSFER_TIMEOUT * (u64)1000000000);
|
||||
eventClear(&(endpoint->CompletionEvent));
|
||||
|
||||
if (R_FAILED(rc))
|
||||
|
|
14
source/usb.h
14
source/usb.h
|
@ -21,7 +21,6 @@
|
|||
|
||||
#include <switch.h>
|
||||
|
||||
#define USB_TRANSFER_ALIGNMENT 0x1000 /* 4 KiB */
|
||||
#define USB_TRANSFER_BUFFER_SIZE 0x800000 /* 8 MiB */
|
||||
|
||||
/// Initializes the USB interface, input and output endpoints and allocates an internal transfer buffer.
|
||||
|
@ -30,17 +29,18 @@ bool usbInitialize(void);
|
|||
/// Closes the USB interface, input and output endpoints and frees the transfer buffer.
|
||||
void usbExit(void);
|
||||
|
||||
/// Checks if the console is currently connected to a host device.
|
||||
bool usbIsHostAvailable(void);
|
||||
/// Returns a pointer to a heap-allocated, page-aligned memory buffer that's suitable for USB transfers.
|
||||
void *usbAllocatePageAlignedBuffer(size_t size);
|
||||
|
||||
/// Performs a handshake with the host device. Returns true if the host device replies with valid data.
|
||||
/// Performs a handshake with the host device. Returns true if the host device replies with valid data within a certain time span.
|
||||
/// This should be called before usbSendFileProperties().
|
||||
bool usbPerformHandshake(void);
|
||||
|
||||
/// Sends file properties to the host device before starting a file data transfer. Must be called before usbSendFileData().
|
||||
/// Sends file properties to the host device before starting a file data transfer. Must be called before usbSendFileData(), and after usbPerformHandshake().
|
||||
bool usbSendFileProperties(u64 file_size, const char *filename);
|
||||
|
||||
/// Performs a file data transfer. Must be called after usbSendFileProperties().
|
||||
/// Performs a file data transfer. Must be continuously called after usbSendFileProperties() until all file data has been transferred.
|
||||
/// Data chunk size must not exceed USB_TRANSFER_BUFFER_SIZE.
|
||||
bool usbSendFileData(void *data, u32 data_size);
|
||||
bool usbSendFileData(void *data, u64 data_size);
|
||||
|
||||
#endif /* __USB_H__ */
|
||||
|
|
Loading…
Reference in a new issue