1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-11-22 18:26:39 +00:00

Additional USB changes.

This commit is contained in:
Pablo Curiel 2020-05-07 07:08:54 -04:00
parent 97f7a46a91
commit 61fb465e2a
3 changed files with 124 additions and 79 deletions

View file

@ -22,7 +22,6 @@
#include <dirent.h> #include <dirent.h>
#include <threads.h> #include <threads.h>
#include <stdarg.h> #include <stdarg.h>
#include <malloc.h>
//#include "lvgl_helper.h" //#include "lvgl_helper.h"
@ -150,7 +149,7 @@ static int read_thread_func(void *arg)
return -1; return -1;
} }
u8 *buf = memalign(USB_TRANSFER_ALIGNMENT, TEST_BUF_SIZE); u8 *buf = usbAllocatePageAlignedBuffer(TEST_BUF_SIZE);
if (!buf) if (!buf)
{ {
shared_data->read_error = true; shared_data->read_error = true;
@ -268,7 +267,10 @@ int main(int argc, char *argv[])
Result rc = 0; 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 // SSBU's Base Program NCA
NcmContentInfo base_program_content_info = { NcmContentInfo base_program_content_info = {
@ -330,7 +332,7 @@ int main(int argc, char *argv[])
consolePrint("ncm open storage succeeded\n"); 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"); consolePrint("base nca initialize ctx failed\n");
goto out2; goto out2;
@ -390,7 +392,7 @@ int main(int argc, char *argv[])
goto out2; 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");*/ 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 = tmp_file;
shared_data.fileobj = NULL; shared_data.fileobj = NULL;
@ -425,36 +437,24 @@ int main(int argc, char *argv[])
consolePrint("waiting for usb connection... "); consolePrint("waiting for usb connection... ");
u8 count = 0; if (!usbPerformHandshake())
while(appletMainLoop())
{ {
/* Avoid using usbIsHostAvailable() alone inside a loop, because it can hang up the system */ consolePrint("failed\n");
consolePrint("%u ", count);
if (usbIsHostAvailable()) break;
utilsSleep(1);
count++;
if (count == 10) break;
}
if (count == 10)
{
consolePrint("\nusb connection not detected\n");
goto out2; goto out2;
} }
consolePrint("\nusb connection detected\n"); consolePrint("success\n");
consolePrint("sending file properties... ");
if (!usbSendFileProperties(shared_data.total_size, "gamecard.xci")) if (!usbSendFileProperties(shared_data.total_size, "gamecard.xci"))
{ {
consolePrint("usb send file properties failed\n"); consolePrint("failed\n");
goto out2; goto out2;
} }
consolePrint("usb send file properties succeeded\n"); consolePrint("success\n");
thrd_t read_thread, write_thread;
consolePrint("creating threads\n\n"); consolePrint("creating threads\n\n");
thrd_create(&read_thread, read_thread_func, &shared_data); thrd_create(&read_thread, read_thread_func, &shared_data);
thrd_create(&write_thread, write_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; 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_time = ts->tm_sec;
prev_size = size; 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); consoleUpdate(NULL);
} }
@ -514,6 +514,7 @@ int main(int argc, char *argv[])
out2: out2:
consolePrint("press any button to exit\n");
utilsWaitForButtonPress(); utilsWaitForButtonPress();
if (tmp_file) fclose(tmp_file); if (tmp_file) fclose(tmp_file);

View file

@ -19,6 +19,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <malloc.h> #include <malloc.h>
#include <time.h>
#include "usb.h" #include "usb.h"
#include "utils.h" #include "utils.h"
@ -27,7 +28,8 @@
#define USB_CMD_HEADER_MAGIC 0x4E584454 /* "NXDT" */ #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. */ /* Type definitions. */
@ -68,17 +70,17 @@ typedef struct {
} UsbCommandSendFileProperties; } UsbCommandSendFileProperties;
typedef enum { typedef enum {
UsbStatusType_Success = 0, UsbStatusType_Success = 0,
UsbStatusType_InvalidCommandSize = 1, UsbStatusType_InvalidCommandSize = 1,
UsbStatusType_WriteCommandFailed = 2, UsbStatusType_WriteCommandFailed = 2,
UsbStatusType_ReadStatusFailed = 3, UsbStatusType_ReadStatusFailed = 3,
UsbStatusType_InvalidMagicWord = 4, UsbStatusType_InvalidMagicWord = 4,
UsbStatusType_MalformedCommand = 5, UsbStatusType_MalformedCommand = 5,
UsbStatusType_UnsupportedAbiVersion = 6, UsbStatusType_UnsupportedAbiVersion = 6,
UsbStatusType_UnsupportedCommand = 7, UsbStatusType_UnsupportedCommand = 7,
UsbStatusType_HostIoError = 8 UsbStatusType_HostIoError = 8
} UsbStatusType; } UsbStatusType;
typedef struct { typedef struct {
@ -98,6 +100,8 @@ static u64 g_usbTransferRemainingSize = 0;
/* Function prototypes. */ /* Function prototypes. */
static bool _usbPerformHandshake(void);
NX_INLINE void usbPrepareCommandHeader(u32 cmd, u32 cmd_block_size); NX_INLINE void usbPrepareCommandHeader(u32 cmd, u32 cmd_block_size);
static u32 usbSendCommand(size_t cmd_size); static u32 usbSendCommand(size_t cmd_size);
NX_INLINE void usbLogStatusDetail(u32 status); NX_INLINE void usbLogStatusDetail(u32 status);
@ -114,8 +118,10 @@ NX_INLINE bool usbInitializeDeviceInterface(void);
static bool usbInitializeDeviceInterface5x(void); static bool usbInitializeDeviceInterface5x(void);
static bool usbInitializeDeviceInterface1x(void); static bool usbInitializeDeviceInterface1x(void);
static bool usbRead(void *buf, size_t size); NX_INLINE bool usbIsHostAvailable(void);
static bool usbWrite(void *buf, size_t size);
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); static bool usbTransferData(void *buf, size_t size, UsbDsEndpoint *endpoint);
bool usbInitialize(void) bool usbInitialize(void)
@ -159,11 +165,10 @@ void usbExit(void)
rwlockWriteUnlock(&g_usbDeviceLock); rwlockWriteUnlock(&g_usbDeviceLock);
} }
bool usbIsHostAvailable(void) void *usbAllocatePageAlignedBuffer(size_t size)
{ {
u32 state = 0; if (!size) return NULL;
usbDsGetState(&state); return memalign(USB_TRANSFER_ALIGNMENT, size);
return (state == 5);
} }
bool usbPerformHandshake(void) bool usbPerformHandshake(void)
@ -172,34 +177,23 @@ bool usbPerformHandshake(void)
rwlockWriteLock(&(g_usbDeviceInterface.lock)); rwlockWriteLock(&(g_usbDeviceInterface.lock));
bool ret = false; bool ret = false;
UsbCommandPerformHandshake *cmd_block = NULL; time_t start = time(NULL);
size_t cmd_size = 0; time_t now = start;
u32 status = UsbStatusType_Success;
if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInitialized || !g_usbDeviceInterface.initialized) while((now - start) < USB_TRANSFER_TIMEOUT)
{ {
LOGFILE("Invalid parameters!"); if (usbIsHostAvailable())
goto exit; {
/* 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_usbDeviceInterface.lock));
rwlockWriteUnlock(&g_usbDeviceLock); rwlockWriteUnlock(&g_usbDeviceLock);
@ -251,7 +245,7 @@ exit:
return ret; return ret;
} }
bool usbSendFileData(void *data, u32 data_size) bool usbSendFileData(void *data, u64 data_size)
{ {
rwlockWriteLock(&g_usbDeviceLock); rwlockWriteLock(&g_usbDeviceLock);
rwlockWriteLock(&(g_usbDeviceInterface.lock)); rwlockWriteLock(&(g_usbDeviceInterface.lock));
@ -317,6 +311,36 @@ exit:
return ret; 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) NX_INLINE void usbPrepareCommandHeader(u32 cmd, u32 cmd_block_size)
{ {
if (cmd > UsbCommandType_SendNspHeader) return; if (cmd > UsbCommandType_SendNspHeader) return;
@ -518,6 +542,19 @@ static bool usbInitializeComms(void)
rc = usbDsSetBinaryObjectStore(bos, sizeof(bos)); rc = usbDsSetBinaryObjectStore(bos, sizeof(bos));
if (R_FAILED(rc)) LOGFILE("usbDsSetBinaryObjectStore failed! (0x%08X)", rc); 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; if (R_FAILED(rc)) goto exit;
@ -822,7 +859,14 @@ static bool usbInitializeDeviceInterface1x(void)
return true; 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)); rwlockWriteLock(&(g_usbDeviceInterface.lock_out));
bool ret = usbTransferData(buf, size, g_usbDeviceInterface.endpoint_out); bool ret = usbTransferData(buf, size, g_usbDeviceInterface.endpoint_out);
@ -830,7 +874,7 @@ static bool usbRead(void *buf, size_t size)
return ret; return ret;
} }
static bool usbWrite(void *buf, size_t size) NX_INLINE bool usbWrite(void *buf, u64 size)
{ {
rwlockWriteLock(&(g_usbDeviceInterface.lock_in)); rwlockWriteLock(&(g_usbDeviceInterface.lock_in));
bool ret = usbTransferData(buf, size, g_usbDeviceInterface.endpoint_in); bool ret = usbTransferData(buf, size, g_usbDeviceInterface.endpoint_in);
@ -838,7 +882,7 @@ static bool usbWrite(void *buf, size_t size)
return ret; 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) 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 */ /* 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)); eventClear(&(endpoint->CompletionEvent));
if (R_FAILED(rc)) if (R_FAILED(rc))

View file

@ -21,7 +21,6 @@
#include <switch.h> #include <switch.h>
#define USB_TRANSFER_ALIGNMENT 0x1000 /* 4 KiB */
#define USB_TRANSFER_BUFFER_SIZE 0x800000 /* 8 MiB */ #define USB_TRANSFER_BUFFER_SIZE 0x800000 /* 8 MiB */
/// Initializes the USB interface, input and output endpoints and allocates an internal transfer buffer. /// 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. /// Closes the USB interface, input and output endpoints and frees the transfer buffer.
void usbExit(void); void usbExit(void);
/// Checks if the console is currently connected to a host device. /// Returns a pointer to a heap-allocated, page-aligned memory buffer that's suitable for USB transfers.
bool usbIsHostAvailable(void); 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); 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); 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. /// 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__ */ #endif /* __USB_H__ */